library(swimplot) library(coxphf) library(grid) library(gtable) library(readr) library(mosaic) library(dplyr) library(officer) library(flextable) library(survival) library(survminer) library(gridtext) library(ggplot2) library(scales) library(ggthemes) library(tidyverse) library(gtsummary) library(flextable) library(parameters) library(car) library(grid) library(ComplexHeatmap) library(readxl) library(janitor) library(rms) library(DT)

#Demographics Table

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]

circ_data_subset <- circ_data %>%
  select(
    Age,
    Gender,
    ECOG,
    pT,
    pN,
    Stage,
    ACT,
    BRAF.V600E,
    RAS,
    MSI,
    RFS.Event,
    OS.Event,
    OS.months) %>%
  mutate(
    Age = as.numeric(Age),
    Gender = factor(Gender, levels = c("Male", "Female")),
    ECOG = factor(ECOG, levels = c(0, 1)),
    pT = factor(pT, levels = c("T1-T2", "T3-T4")),
    pN = factor(pN, levels = c("N0", "N1-N2")),
    Stage = factor(Stage, levels = c("II", "III")),
    ACT = factor(ACT, levels = c("TRUE", "FALSE"), labels = c("Adjuvant Chemotherapy", "Observation")),
    BRAF.V600E = factor(BRAF.V600E, levels = c("WT", "MUT"), labels = c("BRAF wt", "BRAF V600E")),
    RAS = factor(RAS, levels = c("WT", "MUT"), labels = c("RAS wt", "RAS mut")),
    MSI = factor(MSI, levels = c("MSS", "MSI-High")),
    RFS.Event = factor(RFS.Event, levels = c("TRUE", "FALSE"), labels = c("Recurrence", "No Recurrence")),
    OS.Event = factor(OS.Event, levels = c("TRUE", "FALSE"), labels = c("Deceased", "Alive")),
    OS.months = as.numeric(OS.months))
table1 <- circ_data_subset %>%
  tbl_summary(
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  bold_labels()
table1
Characteristic N = 2501
Age 67 (38 - 92)
Gender
    Male 162 (65%)
    Female 88 (35%)
ECOG
    0 228 (91%)
    1 22 (8.8%)
pT
    T1-T2 29 (12%)
    T3-T4 221 (88%)
pN
    N0 99 (40%)
    N1-N2 151 (60%)
Stage
    II 100 (40%)
    III 150 (60%)
ACT
    Adjuvant Chemotherapy 123 (49%)
    Observation 127 (51%)
BRAF.V600E
    BRAF wt 248 (99%)
    BRAF V600E 2 (0.8%)
RAS
    RAS wt 122 (49%)
    RAS mut 128 (51%)
MSI
    MSS 247 (99%)
    MSI-High 3 (1.2%)
RFS.Event
    Recurrence 48 (19%)
    No Recurrence 202 (81%)
OS.Event
    Deceased 11 (4.4%)
    Alive 239 (96%)
OS.months 22.0 (1.2 - 35.9)
1 Median (Min - Max); n (%)
fit1 <- as_flex_table(
  table1,
  include = everything(),
  return_calls = FALSE)
fit1

Characteristic

N = 2501

Age

67 (38 - 92)

Gender

Male

162 (65%)

Female

88 (35%)

ECOG

0

228 (91%)

1

22 (8.8%)

pT

T1-T2

29 (12%)

T3-T4

221 (88%)

pN

N0

99 (40%)

N1-N2

151 (60%)

Stage

II

100 (40%)

III

150 (60%)

ACT

Adjuvant Chemotherapy

123 (49%)

Observation

127 (51%)

BRAF.V600E

BRAF wt

248 (99%)

BRAF V600E

2 (0.8%)

RAS

RAS wt

122 (49%)

RAS mut

128 (51%)

MSI

MSS

247 (99%)

MSI-High

3 (1.2%)

RFS.Event

Recurrence

48 (19%)

No Recurrence

202 (81%)

OS.Event

Deceased

11 (4.4%)

Alive

239 (96%)

OS.months

22.0 (1.2 - 35.9)

1Median (Min - Max); n (%)

save_as_docx(fit1, path= "~/Downloads/table1.docx")

#Demographics Table by MRD ctDNA Status

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]

circ_data_subset1 <- circ_data %>%
  select(
    Age,
    Gender,
    ECOG,
    pT,
    pN,
    Location,
    Stage,
    ACT,
    BRAF.V600E,
    RAS,
    MSI,
    RFS.Event,
    OS.Event,
    OS.months) %>%
  mutate(
    Age = as.numeric(Age),
    Gender = factor(Gender, levels = c("Male", "Female")),
    ECOG = factor(ECOG, levels = c(0, 1)),
    pT = factor(pT, levels = c("T1-T2", "T3-T4")),
    pN = factor(pN, levels = c("N0", "N1-N2")),
    Location = factor(Location, levels = c("Upper rectum (Ra)", "Lower rectum (Rb)")),
    Stage = factor(Stage, levels = c("II", "III")),
    ACT = factor(ACT, levels = c("TRUE", "FALSE"), labels = c("Adjuvant Chemotherapy", "Observation")),
    BRAF.V600E = factor(BRAF.V600E, levels = c("WT", "MUT"), labels = c("BRAF wt", "BRAF V600E")),
    RAS = factor(RAS, levels = c("WT", "MUT"), labels = c("RAS wt", "RAS mut")),
    MSI = factor(MSI, levels = c("MSS", "MSI-High")),
    RFS.Event = factor(RFS.Event, levels = c("TRUE", "FALSE"), labels = c("Recurrence", "No Recurrence")),
    OS.Event = factor(OS.Event, levels = c("TRUE", "FALSE"), labels = c("Deceased", "Alive")),
    OS.months = as.numeric(OS.months))

circ_data1 <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]

circ_data_subset2 <- circ_data %>%
  select(
    Age,
    Gender,
    ECOG,
    pT,
    pN,
    Location,
    Stage,
    ACT,
    BRAF.V600E,
    RAS,
    MSI,
    RFS.Event,
    OS.Event,
    OS.months,
    ctDNA.MRD) %>%
  mutate(
    Age = as.numeric(Age),
    Gender = factor(Gender, levels = c("Male", "Female")),
    ECOG = factor(ECOG, levels = c(0, 1)),
    pT = factor(pT, levels = c("T1-T2", "T3-T4")),
    pN = factor(pN, levels = c("N0", "N1-N2")),
    Location = factor(Location, levels = c("Upper rectum (Ra)", "Lower rectum (Rb)")),
    Stage = factor(Stage, levels = c("II", "III")),
    ACT = factor(ACT, levels = c("TRUE", "FALSE"), labels = c("Adjuvant Chemotherapy", "Observation")),
    BRAF.V600E = factor(BRAF.V600E, levels = c("WT", "MUT"), labels = c("BRAF wt", "BRAF V600E")),
    RAS = factor(RAS, levels = c("WT", "MUT"), labels = c("RAS wt", "RAS mut")),
    MSI = factor(MSI, levels = c("MSS", "MSI-High")),
    RFS.Event = factor(RFS.Event, levels = c("TRUE", "FALSE"), labels = c("Recurrence", "No Recurrence")),
    OS.Event = factor(OS.Event, levels = c("TRUE", "FALSE"), labels = c("Deceased", "Alive")),
    OS.months = as.numeric(OS.months),
    ctDNA.MRD = factor(ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE")))
Overall <- circ_data_subset1 %>%
  tbl_summary(
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  bold_labels()
Overall
Characteristic N = 2471
Age 67 (38 - 92)
Gender
    Male 162 (66%)
    Female 85 (34%)
ECOG
    0 225 (91%)
    1 22 (8.9%)
pT
    T1-T2 29 (12%)
    T3-T4 218 (88%)
pN
    N0 98 (40%)
    N1-N2 149 (60%)
Location
    Upper rectum (Ra) 126 (51%)
    Lower rectum (Rb) 121 (49%)
Stage
    II 99 (40%)
    III 148 (60%)
ACT
    Adjuvant Chemotherapy 121 (49%)
    Observation 126 (51%)
BRAF.V600E
    BRAF wt 245 (99%)
    BRAF V600E 2 (0.8%)
RAS
    RAS wt 121 (49%)
    RAS mut 126 (51%)
MSI
    MSS 244 (99%)
    MSI-High 3 (1.2%)
RFS.Event
    Recurrence 48 (19%)
    No Recurrence 199 (81%)
OS.Event
    Deceased 11 (4.5%)
    Alive 236 (96%)
OS.months 22.0 (1.2 - 35.9)
1 Median (Min - Max); n (%)

ByctDNA_MRD <- circ_data_subset2 %>%
  tbl_summary(
    by = ctDNA.MRD, # add this line to subgroup by ctDNA.MRD
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  add_p() %>%
  bold_labels()
ByctDNA_MRD
Characteristic NEGATIVE
N = 212
1
POSITIVE
N = 35
1
p-value2
Age 67 (38 - 92) 67 (43 - 82) 0.6
Gender

0.5
    Male 141 (67%) 21 (60%)
    Female 71 (33%) 14 (40%)
ECOG

0.3
    0 191 (90%) 34 (97%)
    1 21 (9.9%) 1 (2.9%)
pT

0.8
    T1-T2 26 (12%) 3 (8.6%)
    T3-T4 186 (88%) 32 (91%)
pN

<0.001
    N0 95 (45%) 3 (8.6%)
    N1-N2 117 (55%) 32 (91%)
Location

0.5
    Upper rectum (Ra) 110 (52%) 16 (46%)
    Lower rectum (Rb) 102 (48%) 19 (54%)
Stage

<0.001
    II 96 (45%) 3 (8.6%)
    III 116 (55%) 32 (91%)
ACT

0.004
    Adjuvant Chemotherapy 96 (45%) 25 (71%)
    Observation 116 (55%) 10 (29%)
BRAF.V600E

>0.9
    BRAF wt 210 (99%) 35 (100%)
    BRAF V600E 2 (0.9%) 0 (0%)
RAS

0.060
    RAS wt 109 (51%) 12 (34%)
    RAS mut 103 (49%) 23 (66%)
MSI

>0.9
    MSS 209 (99%) 35 (100%)
    MSI-High 3 (1.4%) 0 (0%)
RFS.Event

<0.001
    Recurrence 23 (11%) 25 (71%)
    No Recurrence 189 (89%) 10 (29%)
OS.Event

0.2
    Deceased 8 (3.8%) 3 (8.6%)
    Alive 204 (96%) 32 (91%)
OS.months 22.0 (7.5 - 35.9) 16.4 (1.2 - 34.9) 0.082
1 Median (Min - Max); n (%)
2 Wilcoxon rank sum test; Pearson’s Chi-squared test; Fisher’s exact test

merged_table <- tbl_merge(tbls=list(Overall, ByctDNA_MRD))
merged_table
Characteristic
Table 1
Table 2
N = 2471 NEGATIVE
N = 212
1
POSITIVE
N = 35
1
p-value2
Age 67 (38 - 92) 67 (38 - 92) 67 (43 - 82) 0.6
Gender


0.5
    Male 162 (66%) 141 (67%) 21 (60%)
    Female 85 (34%) 71 (33%) 14 (40%)
ECOG


0.3
    0 225 (91%) 191 (90%) 34 (97%)
    1 22 (8.9%) 21 (9.9%) 1 (2.9%)
pT


0.8
    T1-T2 29 (12%) 26 (12%) 3 (8.6%)
    T3-T4 218 (88%) 186 (88%) 32 (91%)
pN


<0.001
    N0 98 (40%) 95 (45%) 3 (8.6%)
    N1-N2 149 (60%) 117 (55%) 32 (91%)
Location


0.5
    Upper rectum (Ra) 126 (51%) 110 (52%) 16 (46%)
    Lower rectum (Rb) 121 (49%) 102 (48%) 19 (54%)
Stage


<0.001
    II 99 (40%) 96 (45%) 3 (8.6%)
    III 148 (60%) 116 (55%) 32 (91%)
ACT


0.004
    Adjuvant Chemotherapy 121 (49%) 96 (45%) 25 (71%)
    Observation 126 (51%) 116 (55%) 10 (29%)
BRAF.V600E


>0.9
    BRAF wt 245 (99%) 210 (99%) 35 (100%)
    BRAF V600E 2 (0.8%) 2 (0.9%) 0 (0%)
RAS


0.060
    RAS wt 121 (49%) 109 (51%) 12 (34%)
    RAS mut 126 (51%) 103 (49%) 23 (66%)
MSI


>0.9
    MSS 244 (99%) 209 (99%) 35 (100%)
    MSI-High 3 (1.2%) 3 (1.4%) 0 (0%)
RFS.Event


<0.001
    Recurrence 48 (19%) 23 (11%) 25 (71%)
    No Recurrence 199 (81%) 189 (89%) 10 (29%)
OS.Event


0.2
    Deceased 11 (4.5%) 8 (3.8%) 3 (8.6%)
    Alive 236 (96%) 204 (96%) 32 (91%)
OS.months 22.0 (1.2 - 35.9) 22.0 (7.5 - 35.9) 16.4 (1.2 - 34.9) 0.082
1 Median (Min - Max); n (%)
2 Wilcoxon rank sum test; Pearson’s Chi-squared test; Fisher’s exact test

fit1 <- as_flex_table(
  merged_table,
  include = everything(),
  return_calls = FALSE)
fit1

Table 1

Table 2

Characteristic

N = 2471

NEGATIVE
N = 2121

POSITIVE
N = 351

p-value2

Age

67 (38 - 92)

67 (38 - 92)

67 (43 - 82)

0.6

Gender

0.5

Male

162 (66%)

141 (67%)

21 (60%)

Female

85 (34%)

71 (33%)

14 (40%)

ECOG

0.3

0

225 (91%)

191 (90%)

34 (97%)

1

22 (8.9%)

21 (9.9%)

1 (2.9%)

pT

0.8

T1-T2

29 (12%)

26 (12%)

3 (8.6%)

T3-T4

218 (88%)

186 (88%)

32 (91%)

pN

<0.001

N0

98 (40%)

95 (45%)

3 (8.6%)

N1-N2

149 (60%)

117 (55%)

32 (91%)

Location

0.5

Upper rectum (Ra)

126 (51%)

110 (52%)

16 (46%)

Lower rectum (Rb)

121 (49%)

102 (48%)

19 (54%)

Stage

<0.001

II

99 (40%)

96 (45%)

3 (8.6%)

III

148 (60%)

116 (55%)

32 (91%)

ACT

0.004

Adjuvant Chemotherapy

121 (49%)

96 (45%)

25 (71%)

Observation

126 (51%)

116 (55%)

10 (29%)

BRAF.V600E

>0.9

BRAF wt

245 (99%)

210 (99%)

35 (100%)

BRAF V600E

2 (0.8%)

2 (0.9%)

0 (0%)

RAS

0.060

RAS wt

121 (49%)

109 (51%)

12 (34%)

RAS mut

126 (51%)

103 (49%)

23 (66%)

MSI

>0.9

MSS

244 (99%)

209 (99%)

35 (100%)

MSI-High

3 (1.2%)

3 (1.4%)

0 (0%)

RFS.Event

<0.001

Recurrence

48 (19%)

23 (11%)

25 (71%)

No Recurrence

199 (81%)

189 (89%)

10 (29%)

OS.Event

0.2

Deceased

11 (4.5%)

8 (3.8%)

3 (8.6%)

Alive

236 (96%)

204 (96%)

32 (91%)

OS.months

22.0 (1.2 - 35.9)

22.0 (7.5 - 35.9)

16.4 (1.2 - 34.9)

0.082

1Median (Min - Max); n (%)

2Wilcoxon rank sum test; Pearson's Chi-squared test; Fisher's exact test

save_as_docx(fit1, path= "~/Downloads/merged_table.docx")

#DFS in Complete Cohort (N=250)

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~CohortB, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    CohortB, data = circ_data)

       n events median 0.95LCL 0.95UCL
[1,] 250     53     NA      NA      NA
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ CohortB, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue"), title="DFS - Complete Cohort (n=250)", ylab= "Progression-Free Survival", xlab="Months from Surgery", legend.labs=c("Complete cohort"), legend.title="")

summary(KM_curve, times= c(12, 24, 36))
Call: survfit(formula = surv_object ~ CohortB, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    163      42    0.826  0.0245        0.772        0.868
   24     37      10    0.766  0.0294        0.702        0.818

#OS in Complete Cohort (N=250)

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]

survfit(Surv(time = circ_data$OS.months, event = circ_data$OS.Event)~CohortB, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$OS.months, event = circ_data$OS.Event) ~ 
    CohortB, data = circ_data)

       n events median 0.95LCL 0.95UCL
[1,] 250     11     NA      NA      NA
surv_object <-Surv(time = circ_data$OS.months, event = circ_data$OS.Event)
KM_curve <- survfit(surv_object ~ CohortB, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue"), title="OS - Complete Cohort (n=250)", ylab= "Overall Survival", xlab="Months from Surgery", legend.labs=c("Complete cohort"), legend.title="")

summary(KM_curve, times= c(12, 24, 36))
Call: survfit(formula = surv_object ~ CohortB, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    195       3    0.988 0.00691        0.963        0.996
   24     55       7    0.934 0.02271        0.872        0.966

#ctDNA Detection Rates by Window and Stages

#ctDNA at Baseline
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data$ctDNA.Baseline <- factor(circ_data$ctDNA.Baseline, levels=c("NEGATIVE","POSITIVE"))
circ_data <- subset(circ_data, ctDNA.Baseline %in% c("NEGATIVE", "POSITIVE"))
circ_data$Stage <- factor(circ_data$Stage, levels=c("II", "III"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.Baseline == "POSITIVE", by=list(circ_data$Stage), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.Baseline, by=list(circ_data$Stage), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.Baseline == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA at MRD Window
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
circ_data$Stage <- factor(circ_data$Stage, levels=c("II", "III"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.MRD == "POSITIVE", by=list(circ_data$Stage), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.MRD, by=list(circ_data$Stage), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.MRD == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA at Surveillance Window
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels=c("NEGATIVE","POSITIVE"))
circ_data <- subset(circ_data, ctDNA.Surveillance %in% c("NEGATIVE", "POSITIVE"))
circ_data$Stage <- factor(circ_data$Stage, levels=c("II", "III"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.Surveillance == "POSITIVE", by=list(circ_data$Stage), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.Surveillance, by=list(circ_data$Stage), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.Surveillance == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA MRD Detection rate Stage II vs III

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE"))
circ_data$Stage_Grouped <- factor(ifelse(circ_data$Stage %in% c("II", "II"), "II", "III"))
contingency_table <- table(circ_data$Stage_Grouped, circ_data$ctDNA.MRD)
chi_square_test <- chisq.test(contingency_table)
print(contingency_table)
     
      NEGATIVE POSITIVE
  II        96        3
  III      116       32
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 15.364, df = 1, p-value = 8.865e-05

#ctDNA Surveillance Detection rate Stage II vs III

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels = c("NEGATIVE", "POSITIVE"))
circ_data$Stage_Grouped <- factor(ifelse(circ_data$Stage %in% c("II", "II"), "II", "III"))
contingency_table <- table(circ_data$Stage_Grouped, circ_data$ctDNA.Surveillance)
chi_square_test <- chisq.test(contingency_table)
print(contingency_table)
     
      NEGATIVE POSITIVE
  II        86        8
  III      107       32
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 7.3146, df = 1, p-value = 0.00684

#ctDNA timepoints cadence at the MRD Window

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]

circ_data$MRD_Time_weeks <- circ_data$ctDNA.MRD.Time / 7

# Plot the histogram
hist(circ_data$MRD_Time_weeks,
     col = 'gray',
     main = 'Surgery to first ctDNA testing at MRD window',
     xlab = 'Weeks from surgery to first ctDNA test at MRD window',
     ylab = 'ctDNA Samples',
     ylim = c(0, 120),
     xlim = c(0, 10),
     breaks = seq(0, 24, 1),
     xaxp = c(0, 24, 24))

#DFS by ctDNA at the MRD Window - All stages Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)~ctDNA.MRD, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) ~ 
    ctDNA.MRD, data = circ_data)

                     n events median 0.95LCL 0.95UCL
ctDNA.MRD=NEGATIVE 211     28     NA      NA      NA
ctDNA.MRD=POSITIVE  35     25   9.27    7.62    14.1
event_summary <- circ_data %>%
  group_by(ctDNA.MRD) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.MRD, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA MRD window | All stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(12, 18, 24))
Call: survfit(formula = surv_object ~ ctDNA.MRD, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.MRD=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    146      21    0.895  0.0218        0.843        0.930
   18     97       4    0.868  0.0250        0.810        0.910
   24     31       2    0.850  0.0275        0.787        0.896

                ctDNA.MRD=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      8      22    0.350  0.0830       0.1948        0.509
   18      5       3    0.219  0.0792       0.0884        0.386
   24      2       0    0.219  0.0792       0.0884        0.386
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.MRD, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.MRD, data = circ_data)

  n= 246, number of events= 53 

                    coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.MRDPOSITIVE 2.2985    9.9592   0.2795 8.222   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                  exp(coef) exp(-coef) lower .95 upper .95
ctDNA.MRDPOSITIVE     9.959     0.1004     5.758     17.23

Concordance= 0.709  (se = 0.032 )
Likelihood ratio test= 55.38  on 1 df,   p=1e-13
Wald test            = 67.61  on 1 df,   p=<2e-16
Score (logrank) test = 101.2  on 1 df,   p=<2e-16
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 9.96 (5.76-17.23); p = 0"
#Fisher test for DFS percentages at 12, 18, and 24 months
dfs_times <- c(12, 18, 24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 18 months p-value at 24 months 
        3.289740e-11         6.618049e-13         2.261958e-12 

#Multivariate cox regression at MRD Window for DFS - All stages Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"), labels = c("Negative", "Positive"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ctDNA.MRD + Gender + Age.Group + ECOG + pT + pN + RAS, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for DFS - All Stages", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#DFS by ctDNA at the MRD Window - Stage II Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[!(circ_data$Stage %in% c("III")),]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)~ctDNA.MRD, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) ~ 
    ctDNA.MRD, data = circ_data)

                    n events median 0.95LCL 0.95UCL
ctDNA.MRD=NEGATIVE 96      6     NA      NA      NA
ctDNA.MRD=POSITIVE  3      3     13   0.493      NA
event_summary <- circ_data %>%
  group_by(ctDNA.MRD) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.MRD, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA MRD window | Stage II", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.MRD, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.MRD=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     73       3    0.967  0.0189        0.900        0.989
   24     13       3    0.923  0.0307        0.835        0.965

                ctDNA.MRD=POSITIVE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     12.0000       2.0000       1.0000       0.6667       0.2722       0.0541       0.9452 
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.MRD, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.MRD, data = circ_data)

  n= 99, number of events= 9 

                     coef exp(coef) se(coef)    z Pr(>|z|)    
ctDNA.MRDPOSITIVE  3.3011   27.1423   0.7369 4.48 7.46e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                  exp(coef) exp(-coef) lower .95 upper .95
ctDNA.MRDPOSITIVE     27.14    0.03684     6.404       115

Concordance= 0.66  (se = 0.077 )
Likelihood ratio test= 12.56  on 1 df,   p=4e-04
Wald test            = 20.07  on 1 df,   p=7e-06
Score (logrank) test = 45.99  on 1 df,   p=1e-11
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 27.14 (6.4-115.04); p = 0"
#Fisher test for DFS percentages at 12 and 24 months
dfs_times <- c(12, 24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
        0.1175270483         0.0005355469 

#DFS by ctDNA at the MRD Window - Stage III Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$Eligible=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[!(circ_data$Stage %in% c("II")),]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)~ctDNA.MRD, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) ~ 
    ctDNA.MRD, data = circ_data)

   1 observation deleted due to missingness 
                      n events median 0.95LCL 0.95UCL
ctDNA.MRD=NEGATIVE 1189    203     NA      NA      NA
ctDNA.MRD=POSITIVE  291    233   5.06     4.6    6.51
event_summary <- circ_data %>%
  group_by(ctDNA.MRD) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.MRD, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA MRD window | Stage III", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(24, 30))
Call: survfit(formula = surv_object ~ ctDNA.MRD, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

1 observation deleted due to missingness 
                ctDNA.MRD=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24    391     195    0.806  0.0130        0.779        0.830
   30    228       6    0.791  0.0141        0.762        0.817

                ctDNA.MRD=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24     30     229    0.189  0.0245        0.144        0.239
   30     17       3    0.166  0.0250        0.120        0.218
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.MRD, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.MRD, data = circ_data)

  n= 1480, number of events= 436 
   (1 observation deleted due to missingness)

                     coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.MRDPOSITIVE 2.24488   9.43924  0.09775 22.97   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                  exp(coef) exp(-coef) lower .95 upper .95
ctDNA.MRDPOSITIVE     9.439     0.1059     7.794     11.43

Concordance= 0.729  (se = 0.011 )
Likelihood ratio test= 467.9  on 1 df,   p=<2e-16
Wald test            = 527.5  on 1 df,   p=<2e-16
Score (logrank) test = 768.2  on 1 df,   p=<2e-16
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 9.44 (7.79-11.43); p = 0"
#Fisher test for DFS percentages at 24 and 30 months
dfs_times <- c(24, 30)
circ_data <- na.omit(circ_data[, c("ctDNA.MRD", "DFS.MRD.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 24 months p-value at 30 months 
        6.506858e-91         5.794183e-92 

#DFS by ctDNA at the MRD Window - 2-4 weeks post-surgery

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$MRD_Time_weeks <- circ_data$ctDNA.MRD.Time / 7
circ_data <- circ_data[circ_data$MRD_Time_weeks < 4, ]

survfit(Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)~ctDNA.MRD, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) ~ 
    ctDNA.MRD, data = circ_data)

                     n events median 0.95LCL 0.95UCL
ctDNA.MRD=NEGATIVE 119     17     NA      NA      NA
ctDNA.MRD=POSITIVE  20     15   7.95     4.4      NA
event_summary <- circ_data %>%
  group_by(ctDNA.MRD) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.MRD, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA MRD window | 2-4 weeks", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(12, 18, 24))
Call: survfit(formula = surv_object ~ ctDNA.MRD, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.MRD=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     82      12    0.895  0.0288        0.822        0.939
   18     53       3    0.858  0.0347        0.773        0.913
   24     20       1    0.842  0.0377        0.751        0.902

                ctDNA.MRD=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      4      14    0.281  0.1038       0.1061        0.488
   18      3       1    0.211  0.0988       0.0604        0.422
   24      2       0    0.211  0.0988       0.0604        0.422
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.MRD, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.MRD, data = circ_data)

  n= 139, number of events= 32 

                   coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.MRDPOSITIVE  2.36     10.59     0.36 6.556 5.52e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                  exp(coef) exp(-coef) lower .95 upper .95
ctDNA.MRDPOSITIVE     10.59    0.09442      5.23     21.44

Concordance= 0.721  (se = 0.041 )
Likelihood ratio test= 34.79  on 1 df,   p=4e-09
Wald test            = 42.98  on 1 df,   p=6e-11
Score (logrank) test = 65.6  on 1 df,   p=6e-16
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 10.59 (5.23-21.44); p = 0"
#Fisher test for DFS percentages at 12, 18 and 24 months
dfs_times <- c(12, 18, 24)
circ_data <- na.omit(circ_data[, c("ctDNA.MRD", "DFS.MRD.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 18 months p-value at 24 months 
        3.599476e-08         2.673746e-08         4.960093e-08 

#DFS by ctDNA at the MRD Window - 4-10 weeks post-surgery

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$MRD_Time_weeks <- circ_data$ctDNA.MRD.Time / 7
circ_data <- circ_data[circ_data$MRD_Time_weeks > 4, ]

survfit(Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)~ctDNA.MRD, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) ~ 
    ctDNA.MRD, data = circ_data)

                    n events median 0.95LCL 0.95UCL
ctDNA.MRD=NEGATIVE 88     11     NA      NA      NA
ctDNA.MRD=POSITIVE 13      9   9.27    7.62      NA
event_summary <- circ_data %>%
  group_by(ctDNA.MRD) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.MRD, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA MRD window | 4-10 weeks", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(12, 18, 24))
Call: survfit(formula = surv_object ~ ctDNA.MRD, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.MRD=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     60       9    0.891  0.0345        0.801        0.942
   18     41       1    0.877  0.0370        0.781        0.932
   24     11       1    0.855  0.0418        0.749        0.919

                ctDNA.MRD=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      2       8    0.338   0.137       0.1050        0.594
   18      1       1    0.169   0.138       0.0127        0.485
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.MRD, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.MRD, data = circ_data)

  n= 101, number of events= 20 

                    coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.MRDPOSITIVE 2.2830    9.8061   0.4641 4.919  8.7e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                  exp(coef) exp(-coef) lower .95 upper .95
ctDNA.MRDPOSITIVE     9.806      0.102     3.949     24.35

Concordance= 0.688  (se = 0.053 )
Likelihood ratio test= 19.73  on 1 df,   p=9e-06
Wald test            = 24.2  on 1 df,   p=9e-07
Score (logrank) test = 35.81  on 1 df,   p=2e-09
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 9.81 (3.95-24.35); p = 0"
#Fisher test for DFS percentages at 12, 18 and 24 months
dfs_times <- c(12, 18, 24)
circ_data <- na.omit(circ_data[, c("ctDNA.MRD", "DFS.MRD.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 18 months p-value at 24 months 
        9.794207e-05         2.083220e-05         3.624077e-05 

#DFS by ACT treatment in MRD negative - Stage II/III

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ACT, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ACT, data = circ_data)

            n events median 0.95LCL 0.95UCL
ACT=FALSE 115     16     NA      NA      NA
ACT=TRUE   96     12     NA      NA      NA
event_summary <- circ_data %>%
  group_by(ACT) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ACT, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("red","blue"), title="DFS - ctDNA MRD Negative ACT vs Observation | Stage II/III", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Observation", "ACT"), legend.title="")

summary(KM_curve, times= c(24))
Call: survfit(formula = surv_object ~ ACT, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ACT=FALSE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     24.0000      16.0000      16.0000       0.8419       0.0373       0.7521       0.9013 

                ACT=TRUE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     24.0000      15.0000      11.0000       0.8612       0.0407       0.7574       0.9228 
circ_data$ACT <- factor(circ_data$ACT, levels=c("TRUE","FALSE"))
cox_fit <- coxph(surv_object ~ ACT, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT, data = circ_data)

  n= 211, number of events= 28 

            coef exp(coef) se(coef)     z Pr(>|z|)
ACTFALSE 0.06529   1.06747  0.38220 0.171    0.864

         exp(coef) exp(-coef) lower .95 upper .95
ACTFALSE     1.067     0.9368    0.5047     2.258

Concordance= 0.517  (se = 0.048 )
Likelihood ratio test= 0.03  on 1 df,   p=0.9
Wald test            = 0.03  on 1 df,   p=0.9
Score (logrank) test = 0.03  on 1 df,   p=0.9
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 1.07 (0.5-2.26); p = 0.864"
#Fisher test for DFS percentages at 24
dfs_times <- c(24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ACT == "TRUE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ACT == "FALSE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ACT == "TRUE")
  pos_total <- sum(circ_data$ACT == "FALSE")
  
  neg_surv <- neg_total - sum(circ_data$ACT == "TRUE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  pos_surv <- pos_total - sum(circ_data$ACT == "FALSE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 24 months 
           0.6811626 
#Adjusted HR "ACT vs no ACT" - Non ACT as reference
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ACT <- factor(circ_data$ACT, levels=c("FALSE","TRUE"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", "≥70"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Stage <- factor(circ_data$Stage, levels = c("II", "III"))
circ_data$ECOG <- factor(circ_data$ECOG, levels=c("0","1"))
surv_object <- Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ACT + Gender + Age.Group + Stage + ECOG, data=circ_data)
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT + Gender + Age.Group + Stage + 
    ECOG, data = circ_data)

  n= 211, number of events= 28 

                coef exp(coef) se(coef)      z Pr(>|z|)   
ACTTRUE      -0.5269    0.5904   0.4211 -1.251  0.21080   
GenderMale    0.1145    1.1213   0.4081  0.280  0.77910   
Age.Group≥70  0.3280    1.3883   0.4022  0.816  0.41472   
StageIII      1.5211    4.5774   0.4886  3.113  0.00185 **
ECOG1         0.5215    1.6846   0.5509  0.947  0.34383   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

             exp(coef) exp(-coef) lower .95 upper .95
ACTTRUE         0.5904     1.6937    0.2587     1.348
GenderMale      1.1213     0.8918    0.5039     2.495
Age.Group≥70    1.3883     0.7203    0.6311     3.054
StageIII        4.5774     0.2185    1.7569    11.926
ECOG1           1.6846     0.5936    0.5722     4.960

Concordance= 0.71  (se = 0.043 )
Likelihood ratio test= 12.82  on 5 df,   p=0.03
Wald test            = 11.73  on 5 df,   p=0.04
Score (logrank) test = 12.73  on 5 df,   p=0.03

#DFS by ACT treatment in MRD positive - Stage II/III

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="POSITIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ACT, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ACT, data = circ_data)

           n events median 0.95LCL 0.95UCL
ACT=FALSE  6      5   5.62    1.22      NA
ACT=TRUE  25     16   9.33    6.97      NA
event_summary <- circ_data %>%
  group_by(ACT) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ACT, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("red","blue"), title="DFS - ctDNA MRD Positive ACT vs Observation | Stage II/III", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Observation", "ACT"), legend.title="")

summary(KM_curve, times= c(6, 24))
Call: survfit(formula = surv_object ~ ACT, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ACT=FALSE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
       6.000        2.000        3.000        0.500        0.204        0.111        0.804 

                ACT=TRUE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    6     21       4    0.840  0.0733        0.628        0.937
   24      2      12    0.295  0.1026        0.118        0.497
circ_data$ACT <- factor(circ_data$ACT, levels=c("TRUE","FALSE"))
cox_fit <- coxph(surv_object ~ ACT, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT, data = circ_data)

  n= 31, number of events= 21 

           coef exp(coef) se(coef)     z Pr(>|z|)  
ACTFALSE 1.3036    3.6825   0.5572 2.339   0.0193 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

         exp(coef) exp(-coef) lower .95 upper .95
ACTFALSE     3.682     0.2716     1.235     10.98

Concordance= 0.593  (se = 0.045 )
Likelihood ratio test= 4.59  on 1 df,   p=0.03
Wald test            = 5.47  on 1 df,   p=0.02
Score (logrank) test = 6.25  on 1 df,   p=0.01
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 3.68 (1.24-10.98); p = 0.019"
#Adjusted HR "ACT vs no ACT" - Non ACT as reference
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="POSITIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ACT <- factor(circ_data$ACT, levels=c("FALSE","TRUE"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", "≥70"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Stage <- factor(circ_data$Stage, levels = c("II", "III"))
circ_data$ECOG <- factor(circ_data$ECOG, levels=c("0","1"))
surv_object <- Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ACT + Gender + Age.Group + Stage + ECOG, data=circ_data)
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT + Gender + Age.Group + Stage + 
    ECOG, data = circ_data)

  n= 31, number of events= 21 

                 coef exp(coef) se(coef)      z Pr(>|z|)  
ACTTRUE      -1.27835   0.27850  0.59142 -2.162   0.0307 *
GenderMale    0.35495   1.42611  0.51244  0.693   0.4885  
Age.Group≥70  0.12911   1.13782  0.45951  0.281   0.7787  
StageIII      0.08804   1.09203  0.81274  0.108   0.9137  
ECOG1         1.40597   4.07950  1.13540  1.238   0.2156  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

             exp(coef) exp(-coef) lower .95 upper .95
ACTTRUE         0.2785     3.5907   0.08738    0.8876
GenderMale      1.4261     0.7012   0.52236    3.8935
Age.Group≥70    1.1378     0.8789   0.46231    2.8003
StageIII        1.0920     0.9157   0.22204    5.3708
ECOG1           4.0795     0.2451   0.44071   37.7622

Concordance= 0.632  (se = 0.066 )
Likelihood ratio test= 6.01  on 5 df,   p=0.3
Wald test            = 6.81  on 5 df,   p=0.2
Score (logrank) test = 7.76  on 5 df,   p=0.2

#DFS by ctDNA at 3 months - All stages Landmark 3 months timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.3months!="",]
circ_data <- circ_data[circ_data$DFS.3mo.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event)~ctDNA.3months, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.3months, data = circ_data)

                         n events median 0.95LCL 0.95UCL
ctDNA.3months=NEGATIVE 204     31     NA      NA      NA
ctDNA.3months=POSITIVE  19     14   8.28    5.59      NA
event_summary <- circ_data %>%
  group_by(ctDNA.3months) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.3months, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA 3 months | All stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.3months, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.3months=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    137      26    0.863  0.0252        0.805        0.905
   24     30       4    0.829  0.0293        0.762        0.879

                ctDNA.3months=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      4      14    0.237   0.101       0.0758        0.447
   24      3       0    0.237   0.101       0.0758        0.447
circ_data$ctDNA.3months <- factor(circ_data$ctDNA.3months, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.3months, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.3months, data = circ_data)

  n= 223, number of events= 45 

                        coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.3monthsPOSITIVE 2.0768    7.9792   0.3247 6.397 1.58e-10 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                      exp(coef) exp(-coef) lower .95 upper .95
ctDNA.3monthsPOSITIVE     7.979     0.1253     4.223     15.08

Concordance= 0.641  (se = 0.034 )
Likelihood ratio test= 29.34  on 1 df,   p=6e-08
Wald test            = 40.92  on 1 df,   p=2e-10
Score (logrank) test = 57.62  on 1 df,   p=3e-14
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 7.98 (4.22-15.08); p = 0"
#Fisher test for DFS percentages at 12 and 24 months
dfs_times <- c(12, 24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.3months == "NEGATIVE" & circ_data$DFS.3mo.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.3months == "POSITIVE" & circ_data$DFS.3mo.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.3months == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.3months == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.3months == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.3mo.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.3months == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.3mo.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
        2.546518e-08         1.138180e-07 

#DFS by ctDNA at 6 months - All stages Landmark 6 months timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.6months!="",]
circ_data <- circ_data[circ_data$DFS.6mo.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)~ctDNA.6months, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.6months, data = circ_data)

                         n events median 0.95LCL 0.95UCL
ctDNA.6months=NEGATIVE 173     21     NA      NA      NA
ctDNA.6months=POSITIVE   9      7   3.68     2.6      NA
event_summary <- circ_data %>%
  group_by(ctDNA.6months) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.6months, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA 6 months | All stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(6, 24))
Call: survfit(formula = surv_object ~ ctDNA.6months, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.6months=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    6    134      14    0.915  0.0217        0.861        0.949
   24     14       7    0.832  0.0420        0.730        0.898

                ctDNA.6months=POSITIVE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      6.0000       2.0000       6.0000       0.3333       0.1571       0.0783       0.6226 
circ_data$ctDNA.6months <- factor(circ_data$ctDNA.6months, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.6months, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.6months, data = circ_data)

  n= 182, number of events= 28 

                         coef exp(coef) se(coef)    z Pr(>|z|)    
ctDNA.6monthsPOSITIVE  2.7187   15.1598   0.4577 5.94 2.85e-09 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                      exp(coef) exp(-coef) lower .95 upper .95
ctDNA.6monthsPOSITIVE     15.16    0.06596     6.182     37.18

Concordance= 0.628  (se = 0.042 )
Likelihood ratio test= 22.48  on 1 df,   p=2e-06
Wald test            = 35.29  on 1 df,   p=3e-09
Score (logrank) test = 62.3  on 1 df,   p=3e-15
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 15.16 (6.18-37.18); p = 0"
#Fisher test for DFS percentages at 6 and 24 months
dfs_times <- c(6, 24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.6months == "NEGATIVE" & circ_data$DFS.6mo.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.6months == "POSITIVE" & circ_data$DFS.6mo.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.6months == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.6months == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.6months == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.6mo.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.6months == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.6mo.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
 p-value at 6 months p-value at 24 months 
        5.667547e-05         2.922826e-05 

#DFS by ctDNA Clearance ACT-treated at 3 months - all stages

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",] 
circ_data <- circ_data[circ_data$ACT==TRUE,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "POSITIVE" & ctDNA.3months == "NEGATIVE" ~ 1,
    ctDNA.MRD == "POSITIVE" & ctDNA.3months == "POSITIVE" ~ 2
  ))

circ_data <- circ_data[circ_data$DFS.3mo.months>=0,]
survfit(Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

   97 observations deleted due to missingness 
                  n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1 16      8  14.16    6.01      NA
ctDNA.Dynamics=2  8      7   8.05    5.59      NA
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA Clearance from MRD to 3 months ACT-treated | All Stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Clearance", "No Clearance"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

97 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      5       7    0.516   0.139        0.229        0.742
   24      2       1    0.413   0.145        0.146        0.665

                ctDNA.Dynamics=2 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
    12.00000      1.00000      7.00000      0.12500      0.11693      0.00659      0.42271 
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 24, number of events= 15 
   (97 observations deleted due to missingness)

                             coef exp(coef) se(coef)     z Pr(>|z|)  
ctDNA.DynamicsNo Clearance 0.8707    2.3885   0.5227 1.666   0.0958 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsNo Clearance     2.389     0.4187    0.8574     6.654

Concordance= 0.605  (se = 0.066 )
Likelihood ratio test= 2.65  on 1 df,   p=0.1
Wald test            = 2.77  on 1 df,   p=0.1
Score (logrank) test = 2.95  on 1 df,   p=0.09
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 2.39 (0.86-6.65); p = 0.096"
#Fisher test for DFS percentages at 12 and 24 months
dfs_times <- c(12)
circ_data <- na.omit(circ_data[, c("ctDNA.Dynamics", "DFS.3mo.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.Dynamics == "Clearance" & circ_data$DFS.3mo.months >= time & circ_data$DFS.Event == FALSE)
  pos_count <- sum(circ_data$ctDNA.Dynamics == "No Clearance" & circ_data$DFS.3mo.months >= time & circ_data$DFS.Event == FALSE)
  neg_total <- sum(circ_data$ctDNA.Dynamics == "Clearance")
  pos_total <- sum(circ_data$ctDNA.Dynamics == "No Clearance")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.Dynamics == "Clearance" & circ_data$DFS.Event == TRUE & circ_data$DFS.3mo.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.Dynamics == "No Clearance" & circ_data$DFS.Event == TRUE & circ_data$DFS.3mo.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months 
          0.07907586 

#DFS by ctDNA Clearance ACT-treated at 6 months - all stages

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ACT==TRUE,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "NEGATIVE" ~ 1,
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "POSITIVE" ~ 2
  ))

circ_data <- circ_data[circ_data$DFS.6mo.months>=0,]
survfit(Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

   106 observations deleted due to missingness 
                  n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1 13      5     NA    5.52      NA
ctDNA.Dynamics=2  2      2   2.68    2.60      NA
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA Clearance from MRD to 6 months ACT-treated | All Stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Clearance", "No Clearance"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

106 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      4       5    0.542   0.162        0.204        0.789
   24      2       0    0.542   0.162        0.204        0.789

                ctDNA.Dynamics=2 
     time n.risk n.event survival std.err lower 95% CI upper 95% CI
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 15, number of events= 7 
   (106 observations deleted due to missingness)

                             coef exp(coef) se(coef)    z Pr(>|z|)  
ctDNA.DynamicsNo Clearance  3.017    20.438    1.237 2.44   0.0147 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsNo Clearance     20.44    0.04893      1.81     230.8

Concordance= 0.669  (se = 0.087 )
Likelihood ratio test= 5.94  on 1 df,   p=0.01
Wald test            = 5.95  on 1 df,   p=0.01
Score (logrank) test = 11.68  on 1 df,   p=6e-04
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 20.44 (1.81-230.77); p = 0.015"

#Percentages of MRD negative with molecular recurrence (returned positive) post-MRD

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD != "" & circ_data$Lead.Time >= 0, ]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data <- circ_data[circ_data$PostMRDPos.Event=="TRUE",]
circ_datadf <- as.data.frame(circ_data)

# Convert days to months
circ_data$PostMRDPos.months <- circ_data$PostMRDPos/30.437

# Define the intervals: 0-6, 6-9, 9-12, 12-15, 15-18, 18-21, 21-24, >24 months
breaks <- c(0, 6, 9, 12, 15, 18, 21, 24, 48)
labels <- c("0-6m", "6-9m", "9-12m", "12-15m", "15-18m", "18-21m", "21-24m", ">24m")

# Categorize p_drelReturned_months into intervals
circ_data$p_drelReturned_intervals <- cut(circ_data$PostMRDPos.months, breaks = breaks, labels = labels, right = FALSE)

# Examine the distribution of the intervals
table(circ_data$p_drelReturned_intervals)

  0-6m   6-9m  9-12m 12-15m 15-18m 18-21m 21-24m   >24m 
     9      5      7      1      4      0      0      0 
# Get the counts for each interval
interval_counts <- table(circ_data$p_drelReturned_intervals)

# Calculate the percentages
interval_percentages <- 100 * interval_counts / sum(interval_counts)

# Combine the counts and percentages for a clearer overview
interval_summary <- data.frame(Counts = interval_counts, Percentages = interval_percentages)

# Calculate the total number of observations
total_observations <- sum(interval_counts)

# Add the total number of observations to the summary
interval_summary$TotalObservations <- c(rep(NA, length(interval_counts)-1), total_observations)

# Print the summary with total observations
print(interval_summary)

# Calculate cumulative percentages
cumulative_percentages <- cumsum(interval_percentages)

# Combine the counts, percentages, and cumulative percentages for a clearer overview
interval_summary <- data.frame(Counts = interval_counts, Percentages = interval_percentages, CumulativePercentages = cumulative_percentages, TotalObservations = c(rep(NA, length(interval_counts)-1), total_observations))

bp <- barplot(interval_percentages, 
              main="Molecular Recurrence post-MRD in MRD negative patients", 
              xlab="Months Interval from Surgery", 
              ylab="Patients % converted positive", 
              col="lightblue",
              ylim=c(0, 100))

# Add the cumulative percentages to the plot
points(bp, cumulative_percentages, type="o", pch=22, col="red", cex=1.5)

print(interval_summary)

#DFS by ctDNA MRD positive vs ctDNA negative with molecular recurrence at Surveillance - 3 groups

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="NEGATIVE" ~ 1,
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="POSITIVE" ~ 2,
    ctDNA.MRD == "POSITIVE" ~ 3
  ))

circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
survfit(Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

   7 observations deleted due to missingness 
                   n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1 180     10     NA      NA      NA
ctDNA.Dynamics=2  24     14  13.44   10.55      NA
ctDNA.Dynamics=3  35     25   9.27    7.62    14.1
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","green","red"), title="DFS - ctDNA MRD Pos vs Neg with Molecular Recurrence at Surveillance Window", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("All-time negative","Molecular Recurrence", "ctDNA MRD Positive"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

7 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    131       7    0.959  0.0151        0.916         0.98
   24     28       2    0.942  0.0194        0.889         0.97

                ctDNA.Dynamics=2 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     12      10    0.569   0.104       0.3457        0.742
   24      2       4    0.285   0.122       0.0863        0.525

                ctDNA.Dynamics=3 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      8      22    0.350  0.0830       0.1948        0.509
   24      2       3    0.219  0.0792       0.0884        0.386
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2","3"), labels = c("All-time negative","Molecular Recurrence", "ctDNA MRD Positive"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 239, number of events= 49 
   (7 observations deleted due to missingness)

                                      coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.DynamicsMolecular Recurrence  2.6086   13.5800   0.4162 6.267 3.68e-10 ***
ctDNA.DynamicsctDNA MRD Positive    3.2402   25.5396   0.3786 8.559  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                                   exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsMolecular Recurrence     13.58    0.07364     6.006     30.70
ctDNA.DynamicsctDNA MRD Positive       25.54    0.03915    12.162     53.63

Concordance= 0.834  (se = 0.029 )
Likelihood ratio test= 94.98  on 2 df,   p=<2e-16
Wald test            = 74.17  on 2 df,   p=<2e-16
Score (logrank) test = 146.1  on 2 df,   p=<2e-16
#Fisher test for DFS percentages at 12 and 24 months - All time negative vs Molecular Recurrence
dfs_times <- c(12, 24)
circ_data <- na.omit(circ_data[, c("ctDNA.Dynamics", "DFS.MRD.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.Dynamics == "All-time negative" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.Dynamics == "All-time negative")
  pos_total <- sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.Dynamics == "All-time negative" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
        8.575063e-07         6.424306e-10 
#Repeat analysis to run Fisher test for All time negative vs ctDNA Positive
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="NEGATIVE" ~ 1,
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="POSITIVE" ~ 2,
    ctDNA.MRD == "POSITIVE" ~ 3
  ))

circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]

surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log")
summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

7 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    131       7    0.959  0.0151        0.916         0.98
   24     28       2    0.942  0.0194        0.889         0.97

                ctDNA.Dynamics=2 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     12      10    0.569   0.104       0.3457        0.742
   24      2       4    0.285   0.122       0.0863        0.525

                ctDNA.Dynamics=3 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      8      22    0.350  0.0830       0.1948        0.509
   24      2       3    0.219  0.0792       0.0884        0.386
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2","3"), labels = c("All-time negative","Molecular Recurrence", "ctDNA MRD Positive"))

#Fisher test for DFS percentages at 12 and 24 months - All time negative vs ctDNA Positive
dfs_times <- c(12, 24)
circ_data <- na.omit(circ_data[, c("ctDNA.Dynamics", "DFS.MRD.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.Dynamics == "All-time negative" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.Dynamics == "All-time negative")
  pos_total <- sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.Dynamics == "All-time negative" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
        2.382798e-15         1.933852e-17 
#Repeat analysis to run Fisher test for Molecular Recurrence vs ctDNA Positive
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="NEGATIVE" ~ 1,
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="POSITIVE" ~ 2,
    ctDNA.MRD == "POSITIVE" ~ 3
  ))

circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]

surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log")
summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

7 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    131       7    0.959  0.0151        0.916         0.98
   24     28       2    0.942  0.0194        0.889         0.97

                ctDNA.Dynamics=2 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     12      10    0.569   0.104       0.3457        0.742
   24      2       4    0.285   0.122       0.0863        0.525

                ctDNA.Dynamics=3 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      8      22    0.350  0.0830       0.1948        0.509
   24      2       3    0.219  0.0792       0.0884        0.386
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2","3"), labels = c("All-time negative","Molecular Recurrence", "ctDNA MRD Positive"))

#Fisher test for DFS percentages at 12 and 24 months - Molecular Recurrence vs ctDNA Positive
dfs_times <- c(12, 24)
circ_data <- na.omit(circ_data[, c("ctDNA.Dynamics", "DFS.MRD.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence")
  pos_total <- sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
           0.1214065            0.4023373 
#Repeat to compare HRs for Molecular Recurrence vs ctDNA MRD positive
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="NEGATIVE" ~ 1,
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="POSITIVE" ~ 2,
    ctDNA.MRD == "POSITIVE" ~ 3
  ))

circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("2","3"), labels = c("Molecular Recurrence", "ctDNA MRD Positive"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 59, number of events= 39 
   (187 observations deleted due to missingness)

                                   coef exp(coef) se(coef)     z Pr(>|z|)  
ctDNA.DynamicsctDNA MRD Positive 0.6281    1.8741   0.3361 1.869   0.0616 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                                 exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsctDNA MRD Positive     1.874     0.5336    0.9699     3.621

Concordance= 0.608  (se = 0.037 )
Likelihood ratio test= 3.65  on 1 df,   p=0.06
Wald test            = 3.49  on 1 df,   p=0.06
Score (logrank) test = 3.6  on 1 df,   p=0.06
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 1.87 (0.97-3.62); p = 0.062"

#DFS by ctDNA at the Surveillance Window - All stages Landmark 10 weeks

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Surveillance!="",]
circ_data$DFS.months=circ_data$DFS.months-2.5
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ctDNA.Surveillance, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Surveillance, data = circ_data)

                              n events median 0.95LCL 0.95UCL
ctDNA.Surveillance=NEGATIVE 193     10     NA      NA      NA
ctDNA.Surveillance=POSITIVE  40     30   8.79    7.16      12
event_summary <- circ_data %>%
  group_by(ctDNA.Surveillance) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Surveillance, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA Surveillance window | All stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Surveillance, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.Surveillance=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    138       8    0.955  0.0156        0.912        0.977
   24     31       1    0.946  0.0181        0.896        0.972

                ctDNA.Surveillance=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     12      26    0.336  0.0765       0.1940        0.485
   24      2       4    0.154  0.0733       0.0461        0.321
circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.Surveillance, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Surveillance, data = circ_data)

  n= 233, number of events= 40 

                              coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.SurveillancePOSITIVE  3.2170   24.9530   0.3726 8.633   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.SurveillancePOSITIVE     24.95    0.04008     12.02      51.8

Concordance= 0.822  (se = 0.033 )
Likelihood ratio test= 88.32  on 1 df,   p=<2e-16
Wald test            = 74.53  on 1 df,   p=<2e-16
Score (logrank) test = 156.3  on 1 df,   p=<2e-16
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 24.95 (12.02-51.8); p = 0"
#Fisher test for DFS percentages at 12 and 24 months
dfs_times <- c(12, 24)
circ_data <- na.omit(circ_data[, c("ctDNA.Surveillance", "DFS.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.Surveillance == "NEGATIVE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.Surveillance == "POSITIVE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.Surveillance == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.Surveillance == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.Surveillance == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.Surveillance == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
        1.175567e-17         2.041854e-21 

#Multivariate cox regression at Surveillance Window for DFS - All stages Landmark 10 weeks

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Surveillance!="",]
circ_data$DFS.months=circ_data$DFS.months-2.5
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels=c("NEGATIVE","POSITIVE"), labels = c("Negative", "Positive"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Left-sided colon", "Right-sided colon"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ctDNA.Surveillance + Gender + Age.Group + ECOG + pT + pN + RAS, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for DFS - All Stages", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#DFS by ctDNA Dynamics from MRD to 6 months - all stages

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.6mo.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "NEGATIVE" & ctDNA.6months == "NEGATIVE" ~ 1,
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "NEGATIVE" ~ 2,
    ctDNA.MRD == "NEGATIVE" & ctDNA.6months == "POSITIVE" ~ 3,
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "POSITIVE" ~ 4
  ))

survfit(Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

   66 observations deleted due to missingness 
                   n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1 157     16     NA      NA      NA
ctDNA.Dynamics=2  14      5     NA    5.52      NA
ctDNA.Dynamics=3   4      2   8.51    0.00      NA
ctDNA.Dynamics=4   5      5   2.76    2.60      NA
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","green","purple", "red"), title="DFS - ctDNA Dynamics from MRD to 6 months | All Stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Persistently Negative", "Converted Negative","Converted Positive", "Persistently Positive"), legend.title="")

summary(KM_curve, times= c(24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

66 observations deleted due to missingness 
                ctDNA.Dynamics=1 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      24.000       12.000       16.000        0.851        0.045        0.736        0.919 

                ctDNA.Dynamics=2 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      24.000        2.000        5.000        0.542        0.162        0.204        0.789 

                ctDNA.Dynamics=3 
     time n.risk n.event survival std.err lower 95% CI upper 95% CI

                ctDNA.Dynamics=4 
     time n.risk n.event survival std.err lower 95% CI upper 95% CI
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2","3", "4"), labels = c("Persistently Negative", "Converted Negative","Converted Positive", "Persistently Positive"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 180, number of events= 28 
   (66 observations deleted due to missingness)

                                       coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.DynamicsConverted Negative     1.5689    4.8013   0.5147 3.048  0.00230 ** 
ctDNA.DynamicsConverted Positive     2.1062    8.2170   0.7582 2.778  0.00547 ** 
ctDNA.DynamicsPersistently Positive  3.8173   45.4828   0.5900 6.470  9.8e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                                    exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsConverted Negative        4.801    0.20828     1.751     13.17
ctDNA.DynamicsConverted Positive        8.217    0.12170     1.859     36.32
ctDNA.DynamicsPersistently Positive    45.483    0.02199    14.310    144.57

Concordance= 0.697  (se = 0.048 )
Likelihood ratio test= 33.4  on 3 df,   p=3e-07
Wald test            = 46.4  on 3 df,   p=5e-10
Score (logrank) test = 106.2  on 3 df,   p=<2e-16

#Table with recurrence sites by ctDNA at the MRD Window

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]

circ_data_subset1 <- circ_data %>%
  select(
    Rel.Site) %>%
  mutate(
    Rel.Site = factor(Rel.Site, levels = c("Local", "Lymph Node", "Liver", "Lung", "Peritoneum", "Brain")))

circ_data_subset2 <- circ_data %>%
  select(
    Rel.Site,
    ctDNA.MRD) %>%
  mutate(
    Rel.Site = factor(Rel.Site, levels = c("Local", "Lymph Node", "Liver", "Lung", "Peritoneum", "Brain")),
    ctDNA.MRD = factor(ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE")))
Overall <- circ_data_subset1 %>%
  tbl_summary(
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  bold_labels()
Overall
Characteristic N = 481
Rel.Site
    Local 4 (8.3%)
    Lymph Node 5 (10%)
    Liver 17 (35%)
    Lung 18 (38%)
    Peritoneum 3 (6.3%)
    Brain 1 (2.1%)
1 n (%)

ByctDNA_MRD <- circ_data_subset2 %>%
  tbl_summary(
    by = ctDNA.MRD, # add this line to subgroup by ctDNA.MRD
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  add_p() %>%
  bold_labels()
ByctDNA_MRD
Characteristic NEGATIVE
N = 23
1
POSITIVE
N = 25
1
p-value2
Rel.Site

<0.001
    Local 2 (8.7%) 2 (8.0%)
    Lymph Node 1 (4.3%) 4 (16%)
    Liver 2 (8.7%) 15 (60%)
    Lung 15 (65%) 3 (12%)
    Peritoneum 2 (8.7%) 1 (4.0%)
    Brain 1 (4.3%) 0 (0%)
1 n (%)
2 Fisher’s exact test

merged_table <- tbl_merge(tbls=list(Overall, ByctDNA_MRD))
merged_table
Characteristic
Table 1
Table 2
N = 481 NEGATIVE
N = 23
1
POSITIVE
N = 25
1
p-value2
Rel.Site


<0.001
    Local 4 (8.3%) 2 (8.7%) 2 (8.0%)
    Lymph Node 5 (10%) 1 (4.3%) 4 (16%)
    Liver 17 (35%) 2 (8.7%) 15 (60%)
    Lung 18 (38%) 15 (65%) 3 (12%)
    Peritoneum 3 (6.3%) 2 (8.7%) 1 (4.0%)
    Brain 1 (2.1%) 1 (4.3%) 0 (0%)
1 n (%)
2 Fisher’s exact test

fit1 <- as_flex_table(
  merged_table,
  include = everything(),
  return_calls = FALSE)
fit1

Table 1

Table 2

Characteristic

N = 481

NEGATIVE
N = 231

POSITIVE
N = 251

p-value2

Rel.Site

<0.001

Local

4 (8.3%)

2 (8.7%)

2 (8.0%)

Lymph Node

5 (10%)

1 (4.3%)

4 (16%)

Liver

17 (35%)

2 (8.7%)

15 (60%)

Lung

18 (38%)

15 (65%)

3 (12%)

Peritoneum

3 (6.3%)

2 (8.7%)

1 (4.0%)

Brain

1 (2.1%)

1 (4.3%)

0 (0%)

1n (%)

2Fisher's exact test

save_as_docx(fit1, path= "~/Downloads/merged_table.docx")

#MTM/mL levels at the MRD Window by Radiological Recurrence

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_data <- as.data.frame(circ_data)

# Transform p_MRD_MTM with log10
circ_data$p_MRD_MTM <- as.numeric(as.character(circ_data$p_MRD_MTM))
circ_data$RFS.Event <- factor(circ_data$RFS.Event, levels = c("FALSE", "TRUE"), labels = c("No Recurrence", "Recurrence"))
summary_stats <- circ_data %>%
  group_by(RFS.Event) %>%
  summarise(
    median_p_MRD_MTM = median(p_MRD_MTM, na.rm = TRUE),
    range_p_MRD_MTM = paste0(min(p_MRD_MTM, na.rm = TRUE), " - ", max(p_MRD_MTM, na.rm = TRUE))
  )
print(summary_stats)

m3_1v2 <- wilcox.test(p_MRD_MTM ~ RFS.Event,
                      data = circ_data[circ_data$RFS.Event %in% c("No Recurrence", "Recurrence"), ],
                      na.rm = TRUE)
print(m3_1v2)

    Wilcoxon rank sum test with continuity correction

data:  p_MRD_MTM by RFS.Event
W = 2458, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0
boxplot(p_MRD_MTM~RFS.Event, data=circ_data, main="ctDNA MRD Window MTM - Recurrence", xlab="Recurrence", ylab="MTM/mL", col="white",border="black", ylim = c(0, 50))

#MTM/mL levels at the MRD Window by Radiological Recurrence Sites

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_data <- as.data.frame(circ_data)

# Transform p_MRD_MTM with log10
circ_data$p_MRD_MTM <- as.numeric(as.character(circ_data$p_MRD_MTM))
circ_data$Rel.Site <- factor(circ_data$Rel.Site, levels = c("Liver", "Lymph Node", "Local", "Peritoneum", "Lung", "Brain"))
summary_stats <- circ_data %>%
  group_by(Rel.Site) %>%
  summarise(
    median_p_MRD_MTM = median(p_MRD_MTM, na.rm = TRUE),
    range_p_MRD_MTM = paste0(min(p_MRD_MTM, na.rm = TRUE), " - ", max(p_MRD_MTM, na.rm = TRUE))
  )
print(summary_stats)
kruskal_test <- kruskal.test(p_MRD_MTM ~ Rel.Site, data = circ_data)
print(kruskal_test)

    Kruskal-Wallis rank sum test

data:  p_MRD_MTM by Rel.Site
Kruskal-Wallis chi-squared = 20.366, df = 5, p-value = 0.001067
boxplot(p_MRD_MTM~Rel.Site, data=circ_data, main="ctDNA MRD Window MTM - Recurrence Site", xlab="Recurrence Site", ylab="MTM/mL", col="white",border="black", ylim = c(0, 40))

#Barplot with Recurrence Sites (Liver vs Others) by ctDNA at the MRD Window

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]

circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
circ_data$Rel.Site <- factor(circ_data$Rel.Site, levels = c("Liver", "Lymph Node", "Local", "Peritoneum", "Lung", "Brain"))
contingency_table <- table(circ_data$Rel.Site, circ_data$ctDNA.MRD)
chi_square_test <- chisq.test(contingency_table)
G2;H2;Warningh in stats::chisq.test(x, y, ...) :
  Chi-squared approximation may be incorrectg
print(chi_square_test)

    Pearson's Chi-squared test

data:  contingency_table
X-squared = 21.028, df = 5, p-value = 0.0008004
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 5.02e-05
alternative hypothesis: two.sided
print(contingency_table)
            
             Negative Positive
  Liver             2       15
  Lymph Node        1        4
  Local             2        2
  Peritoneum        2        1
  Lung             15        3
  Brain             1        0
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "Patients with Radiological Recurrence", 
       x = "Recurrence Site", 
       y = "Patients (%)", 
       fill = "ctDNA at MRD",
       caption = paste("Chi-squared test p-value: ", format.pval(chi_square_test$p.value))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("Negative" = "blue", "Positive" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Recurrence label size

#Detection ctDNA rates based on sites of relapse

# Remove existing objects and set the working directory
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]

# Create a table of counts for the "Rel.Site" variable
relsite_counts <- table(circ_data$Rel.Site)
relsite_df <- as.data.frame(relsite_counts)
names(relsite_df) <- c("Rel.Site", "Count")
circ_data_pos_mrd <- circ_data[circ_data$ctDNA.MRD=="POSITIVE",]
circ_data_pos_anytime <- circ_data[circ_data$ctDNA.anytime=="POSITIVE",]
pos_counts_mrd <- table(circ_data_pos_mrd$Rel.Site)
pos_counts_anytime <- table(circ_data_pos_anytime$Rel.Site)
relsite_df$MRDPos_Count <- ifelse(is.na(match(relsite_df$Rel.Site, names(pos_counts_mrd))), 0, pos_counts_mrd[match(relsite_df$Rel.Site, names(pos_counts_mrd))])
relsite_df$MRDPos_Count[is.na(relsite_df$MRDPos_Count)] <- 0
relsite_df$AnytimePos_Count <- ifelse(is.na(match(relsite_df$Rel.Site, names(pos_counts_anytime))), 0, pos_counts_anytime[match(relsite_df$Rel.Site, names(pos_counts_anytime))])
relsite_df$AnytimePos_Count[is.na(relsite_df$AnytimePos_Count)] <- 0
relsite_df$Percent <- (relsite_df$Count / sum(relsite_df$Count)) * 100
relsite_df$MRDPos_Percent <- (relsite_df$MRDPos_Count / relsite_df$Count) * 100
relsite_df$AnytimePos_Percent <- (relsite_df$AnytimePos_Count / relsite_df$Count) * 100
total_observations <- sum(relsite_df$Count)
total_pos_mrd <- sum(relsite_df$MRDPos_Count)
total_pos_anytime <- sum(relsite_df$AnytimePos_Count)
total_row <- data.frame(Rel.Site = "Total", Count = total_observations, MRDPos_Count = total_pos_mrd, AnytimePos_Count = total_pos_anytime, Percent = 100, MRDPos_Percent = (total_pos_mrd / total_observations) * 100, AnytimePos_Percent = (total_pos_anytime / total_observations) * 100)
relsite_df <- rbind(relsite_df, total_row)
print(relsite_df)

ft <- flextable(relsite_df)
doc <- read_docx() %>%
  body_add_flextable(value = ft)
print(doc, target = "relsite_df.docx")
LS0tCnRpdGxlOiAiQ0lSQ1VMQVRFIEdhbGF4eSBjb2hvcnQgQiBBbmRvIGV0IGFsIDIwMjQiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmxpYnJhcnkoc3dpbXBsb3QpCmxpYnJhcnkoY294cGhmKQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoZ3RhYmxlKQpsaWJyYXJ5KHJlYWRyKSAKbGlicmFyeShtb3NhaWMpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkob2ZmaWNlcikKbGlicmFyeShmbGV4dGFibGUpCmxpYnJhcnkoc3Vydml2YWwpIApsaWJyYXJ5KHN1cnZtaW5lcikKbGlicmFyeShncmlkdGV4dCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ3RzdW1tYXJ5KQpsaWJyYXJ5KGZsZXh0YWJsZSkKbGlicmFyeShwYXJhbWV0ZXJzKQpsaWJyYXJ5KGNhcikKbGlicmFyeShncmlkKQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KHJtcykKbGlicmFyeShEVCkKCiNEZW1vZ3JhcGhpY3MgVGFibGUKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCgpjaXJjX2RhdGFfc3Vic2V0IDwtIGNpcmNfZGF0YSAlPiUKICBzZWxlY3QoCiAgICBBZ2UsCiAgICBHZW5kZXIsCiAgICBFQ09HLAogICAgcFQsCiAgICBwTiwKICAgIFN0YWdlLAogICAgQUNULAogICAgQlJBRi5WNjAwRSwKICAgIFJBUywKICAgIE1TSSwKICAgIFJGUy5FdmVudCwKICAgIE9TLkV2ZW50LAogICAgT1MubW9udGhzKSAlPiUKICBtdXRhdGUoCiAgICBBZ2UgPSBhcy5udW1lcmljKEFnZSksCiAgICBHZW5kZXIgPSBmYWN0b3IoR2VuZGVyLCBsZXZlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpKSwKICAgIEVDT0cgPSBmYWN0b3IoRUNPRywgbGV2ZWxzID0gYygwLCAxKSksCiAgICBwVCA9IGZhY3RvcihwVCwgbGV2ZWxzID0gYygiVDEtVDIiLCAiVDMtVDQiKSksCiAgICBwTiA9IGZhY3RvcihwTiwgbGV2ZWxzID0gYygiTjAiLCAiTjEtTjIiKSksCiAgICBTdGFnZSA9IGZhY3RvcihTdGFnZSwgbGV2ZWxzID0gYygiSUkiLCAiSUlJIikpLAogICAgQUNUID0gZmFjdG9yKEFDVCwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJBZGp1dmFudCBDaGVtb3RoZXJhcHkiLCAiT2JzZXJ2YXRpb24iKSksCiAgICBCUkFGLlY2MDBFID0gZmFjdG9yKEJSQUYuVjYwMEUsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJCUkFGIHd0IiwgIkJSQUYgVjYwMEUiKSksCiAgICBSQVMgPSBmYWN0b3IoUkFTLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiUkFTIHd0IiwgIlJBUyBtdXQiKSksCiAgICBNU0kgPSBmYWN0b3IoTVNJLCBsZXZlbHMgPSBjKCJNU1MiLCAiTVNJLUhpZ2giKSksCiAgICBSRlMuRXZlbnQgPSBmYWN0b3IoUkZTLkV2ZW50LCBsZXZlbHMgPSBjKCJUUlVFIiwgIkZBTFNFIiksIGxhYmVscyA9IGMoIlJlY3VycmVuY2UiLCAiTm8gUmVjdXJyZW5jZSIpKSwKICAgIE9TLkV2ZW50ID0gZmFjdG9yKE9TLkV2ZW50LCBsZXZlbHMgPSBjKCJUUlVFIiwgIkZBTFNFIiksIGxhYmVscyA9IGMoIkRlY2Vhc2VkIiwgIkFsaXZlIikpLAogICAgT1MubW9udGhzID0gYXMubnVtZXJpYyhPUy5tb250aHMpKQp0YWJsZTEgPC0gY2lyY19kYXRhX3N1YnNldCAlPiUKICB0Ymxfc3VtbWFyeSgKICAgIHN0YXRpc3RpYyA9IGxpc3QoCiAgICAgIGFsbF9jb250aW51b3VzKCkgfiAie21lZGlhbn0gKHttaW59IC0ge21heH0pIiwKICAgICAgYWxsX2NhdGVnb3JpY2FsKCkgfiAie259ICh7cH0lKSIpKSAlPiUKICBib2xkX2xhYmVscygpCnRhYmxlMQpmaXQxIDwtIGFzX2ZsZXhfdGFibGUoCiAgdGFibGUxLAogIGluY2x1ZGUgPSBldmVyeXRoaW5nKCksCiAgcmV0dXJuX2NhbGxzID0gRkFMU0UpCmZpdDEKc2F2ZV9hc19kb2N4KGZpdDEsIHBhdGg9ICJ+L0Rvd25sb2Fkcy90YWJsZTEuZG9jeCIpCmBgYAoKCiNEZW1vZ3JhcGhpY3MgVGFibGUgYnkgTVJEIGN0RE5BIFN0YXR1cwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCgpjaXJjX2RhdGFfc3Vic2V0MSA8LSBjaXJjX2RhdGEgJT4lCiAgc2VsZWN0KAogICAgQWdlLAogICAgR2VuZGVyLAogICAgRUNPRywKICAgIHBULAogICAgcE4sCiAgICBMb2NhdGlvbiwKICAgIFN0YWdlLAogICAgQUNULAogICAgQlJBRi5WNjAwRSwKICAgIFJBUywKICAgIE1TSSwKICAgIFJGUy5FdmVudCwKICAgIE9TLkV2ZW50LAogICAgT1MubW9udGhzKSAlPiUKICBtdXRhdGUoCiAgICBBZ2UgPSBhcy5udW1lcmljKEFnZSksCiAgICBHZW5kZXIgPSBmYWN0b3IoR2VuZGVyLCBsZXZlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpKSwKICAgIEVDT0cgPSBmYWN0b3IoRUNPRywgbGV2ZWxzID0gYygwLCAxKSksCiAgICBwVCA9IGZhY3RvcihwVCwgbGV2ZWxzID0gYygiVDEtVDIiLCAiVDMtVDQiKSksCiAgICBwTiA9IGZhY3RvcihwTiwgbGV2ZWxzID0gYygiTjAiLCAiTjEtTjIiKSksCiAgICBMb2NhdGlvbiA9IGZhY3RvcihMb2NhdGlvbiwgbGV2ZWxzID0gYygiVXBwZXIgcmVjdHVtIChSYSkiLCAiTG93ZXIgcmVjdHVtIChSYikiKSksCiAgICBTdGFnZSA9IGZhY3RvcihTdGFnZSwgbGV2ZWxzID0gYygiSUkiLCAiSUlJIikpLAogICAgQUNUID0gZmFjdG9yKEFDVCwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJBZGp1dmFudCBDaGVtb3RoZXJhcHkiLCAiT2JzZXJ2YXRpb24iKSksCiAgICBCUkFGLlY2MDBFID0gZmFjdG9yKEJSQUYuVjYwMEUsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJCUkFGIHd0IiwgIkJSQUYgVjYwMEUiKSksCiAgICBSQVMgPSBmYWN0b3IoUkFTLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiUkFTIHd0IiwgIlJBUyBtdXQiKSksCiAgICBNU0kgPSBmYWN0b3IoTVNJLCBsZXZlbHMgPSBjKCJNU1MiLCAiTVNJLUhpZ2giKSksCiAgICBSRlMuRXZlbnQgPSBmYWN0b3IoUkZTLkV2ZW50LCBsZXZlbHMgPSBjKCJUUlVFIiwgIkZBTFNFIiksIGxhYmVscyA9IGMoIlJlY3VycmVuY2UiLCAiTm8gUmVjdXJyZW5jZSIpKSwKICAgIE9TLkV2ZW50ID0gZmFjdG9yKE9TLkV2ZW50LCBsZXZlbHMgPSBjKCJUUlVFIiwgIkZBTFNFIiksIGxhYmVscyA9IGMoIkRlY2Vhc2VkIiwgIkFsaXZlIikpLAogICAgT1MubW9udGhzID0gYXMubnVtZXJpYyhPUy5tb250aHMpKQoKY2lyY19kYXRhMSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KCmNpcmNfZGF0YV9zdWJzZXQyIDwtIGNpcmNfZGF0YSAlPiUKICBzZWxlY3QoCiAgICBBZ2UsCiAgICBHZW5kZXIsCiAgICBFQ09HLAogICAgcFQsCiAgICBwTiwKICAgIExvY2F0aW9uLAogICAgU3RhZ2UsCiAgICBBQ1QsCiAgICBCUkFGLlY2MDBFLAogICAgUkFTLAogICAgTVNJLAogICAgUkZTLkV2ZW50LAogICAgT1MuRXZlbnQsCiAgICBPUy5tb250aHMsCiAgICBjdEROQS5NUkQpICU+JQogIG11dGF0ZSgKICAgIEFnZSA9IGFzLm51bWVyaWMoQWdlKSwKICAgIEdlbmRlciA9IGZhY3RvcihHZW5kZXIsIGxldmVscyA9IGMoIk1hbGUiLCAiRmVtYWxlIikpLAogICAgRUNPRyA9IGZhY3RvcihFQ09HLCBsZXZlbHMgPSBjKDAsIDEpKSwKICAgIHBUID0gZmFjdG9yKHBULCBsZXZlbHMgPSBjKCJUMS1UMiIsICJUMy1UNCIpKSwKICAgIHBOID0gZmFjdG9yKHBOLCBsZXZlbHMgPSBjKCJOMCIsICJOMS1OMiIpKSwKICAgIExvY2F0aW9uID0gZmFjdG9yKExvY2F0aW9uLCBsZXZlbHMgPSBjKCJVcHBlciByZWN0dW0gKFJhKSIsICJMb3dlciByZWN0dW0gKFJiKSIpKSwKICAgIFN0YWdlID0gZmFjdG9yKFN0YWdlLCBsZXZlbHMgPSBjKCJJSSIsICJJSUkiKSksCiAgICBBQ1QgPSBmYWN0b3IoQUNULCBsZXZlbHMgPSBjKCJUUlVFIiwgIkZBTFNFIiksIGxhYmVscyA9IGMoIkFkanV2YW50IENoZW1vdGhlcmFweSIsICJPYnNlcnZhdGlvbiIpKSwKICAgIEJSQUYuVjYwMEUgPSBmYWN0b3IoQlJBRi5WNjAwRSwgbGV2ZWxzID0gYygiV1QiLCAiTVVUIiksIGxhYmVscyA9IGMoIkJSQUYgd3QiLCAiQlJBRiBWNjAwRSIpKSwKICAgIFJBUyA9IGZhY3RvcihSQVMsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJSQVMgd3QiLCAiUkFTIG11dCIpKSwKICAgIE1TSSA9IGZhY3RvcihNU0ksIGxldmVscyA9IGMoIk1TUyIsICJNU0ktSGlnaCIpKSwKICAgIFJGUy5FdmVudCA9IGZhY3RvcihSRlMuRXZlbnQsIGxldmVscyA9IGMoIlRSVUUiLCAiRkFMU0UiKSwgbGFiZWxzID0gYygiUmVjdXJyZW5jZSIsICJObyBSZWN1cnJlbmNlIikpLAogICAgT1MuRXZlbnQgPSBmYWN0b3IoT1MuRXZlbnQsIGxldmVscyA9IGMoIlRSVUUiLCAiRkFMU0UiKSwgbGFiZWxzID0gYygiRGVjZWFzZWQiLCAiQWxpdmUiKSksCiAgICBPUy5tb250aHMgPSBhcy5udW1lcmljKE9TLm1vbnRocyksCiAgICBjdEROQS5NUkQgPSBmYWN0b3IoY3RETkEuTVJELCBsZXZlbHMgPSBjKCJORUdBVElWRSIsICJQT1NJVElWRSIpKSkKT3ZlcmFsbCA8LSBjaXJjX2RhdGFfc3Vic2V0MSAlPiUKICB0Ymxfc3VtbWFyeSgKICAgIHN0YXRpc3RpYyA9IGxpc3QoCiAgICAgIGFsbF9jb250aW51b3VzKCkgfiAie21lZGlhbn0gKHttaW59IC0ge21heH0pIiwKICAgICAgYWxsX2NhdGVnb3JpY2FsKCkgfiAie259ICh7cH0lKSIpKSAlPiUKICBib2xkX2xhYmVscygpCk92ZXJhbGwKCkJ5Y3RETkFfTVJEIDwtIGNpcmNfZGF0YV9zdWJzZXQyICU+JQogIHRibF9zdW1tYXJ5KAogICAgYnkgPSBjdEROQS5NUkQsICMgYWRkIHRoaXMgbGluZSB0byBzdWJncm91cCBieSBjdEROQS5NUkQKICAgIHN0YXRpc3RpYyA9IGxpc3QoCiAgICAgIGFsbF9jb250aW51b3VzKCkgfiAie21lZGlhbn0gKHttaW59IC0ge21heH0pIiwKICAgICAgYWxsX2NhdGVnb3JpY2FsKCkgfiAie259ICh7cH0lKSIpKSAlPiUKICBhZGRfcCgpICU+JQogIGJvbGRfbGFiZWxzKCkKQnljdEROQV9NUkQKCm1lcmdlZF90YWJsZSA8LSB0YmxfbWVyZ2UodGJscz1saXN0KE92ZXJhbGwsIEJ5Y3RETkFfTVJEKSkKbWVyZ2VkX3RhYmxlCgpmaXQxIDwtIGFzX2ZsZXhfdGFibGUoCiAgbWVyZ2VkX3RhYmxlLAogIGluY2x1ZGUgPSBldmVyeXRoaW5nKCksCiAgcmV0dXJuX2NhbGxzID0gRkFMU0UpCmZpdDEKc2F2ZV9hc19kb2N4KGZpdDEsIHBhdGg9ICJ+L0Rvd25sb2Fkcy9tZXJnZWRfdGFibGUuZG9jeCIpCmBgYAoKI0RGUyBpbiBDb21wbGV0ZSBDb2hvcnQgKE49MjUwKQpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpfkNvaG9ydEIsIGRhdGEgPSBjaXJjX2RhdGEpCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IENvaG9ydEIsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiKSwgdGl0bGU9IkRGUyAtIENvbXBsZXRlIENvaG9ydCAobj0yNTApIiwgeWxhYj0gIlByb2dyZXNzaW9uLUZyZWUgU3Vydml2YWwiLCB4bGFiPSJNb250aHMgZnJvbSBTdXJnZXJ5IiwgbGVnZW5kLmxhYnM9YygiQ29tcGxldGUgY29ob3J0IiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDI0LCAzNikpCmBgYAoKI09TIGluIENvbXBsZXRlIENvaG9ydCAoTj0yNTApCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJE9TLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkT1MuRXZlbnQpfkNvaG9ydEIsIGRhdGEgPSBjaXJjX2RhdGEpCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJE9TLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkT1MuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBDb2hvcnRCLCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiksIHRpdGxlPSJPUyAtIENvbXBsZXRlIENvaG9ydCAobj0yNTApIiwgeWxhYj0gIk92ZXJhbGwgU3Vydml2YWwiLCB4bGFiPSJNb250aHMgZnJvbSBTdXJnZXJ5IiwgbGVnZW5kLmxhYnM9YygiQ29tcGxldGUgY29ob3J0IiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDI0LCAzNikpCmBgYAoKI2N0RE5BIERldGVjdGlvbiBSYXRlcyBieSBXaW5kb3cgYW5kIFN0YWdlcwpgYGB7cn0KI2N0RE5BIGF0IEJhc2VsaW5lCnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSRjdEROQS5CYXNlbGluZSA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkJhc2VsaW5lLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjaXJjX2RhdGEgPC0gc3Vic2V0KGNpcmNfZGF0YSwgY3RETkEuQmFzZWxpbmUgJWluJSBjKCJORUdBVElWRSIsICJQT1NJVElWRSIpKQpjaXJjX2RhdGEkU3RhZ2UgPC0gZmFjdG9yKGNpcmNfZGF0YSRTdGFnZSwgbGV2ZWxzPWMoIklJIiwgIklJSSIpKQpwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UgPC0gYWdncmVnYXRlKGNpcmNfZGF0YSRjdEROQS5CYXNlbGluZSA9PSAiUE9TSVRJVkUiLCBieT1saXN0KGNpcmNfZGF0YSRTdGFnZSksIEZVTj1zdW0pCnRvdGFsX2NvdW50c19ieV9zdGFnZSA8LSBhZ2dyZWdhdGUoY2lyY19kYXRhJGN0RE5BLkJhc2VsaW5lLCBieT1saXN0KGNpcmNfZGF0YSRTdGFnZSksIEZVTj1sZW5ndGgpCmNvbWJpbmVkX2RhdGEgPC0gZGF0YS5mcmFtZSgKICBTdGFnZSA9IHRvdGFsX2NvdW50c19ieV9zdGFnZSRHcm91cC4xLAogIFRvdGFsX0NvdW50ID0gdG90YWxfY291bnRzX2J5X3N0YWdlJHgsCiAgUG9zaXRpdmVfQ291bnQgPSBwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UkeCwKICBSYXRlID0gKHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4IC8gdG90YWxfY291bnRzX2J5X3N0YWdlJHgpICogMTAwICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQopCmNvbWJpbmVkX2RhdGEkUmF0ZSA8LSBzcHJpbnRmKCIlLjJmJSUiLCBjb21iaW5lZF9kYXRhJFJhdGUpCm92ZXJhbGxfdG90YWxfY291bnQgPC0gbnJvdyhjaXJjX2RhdGEpCm92ZXJhbGxfcG9zaXRpdmVfY291bnQgPC0gbnJvdyhjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2VsaW5lID09ICJQT1NJVElWRSIsXSkKb3ZlcmFsbF9wb3NpdGl2aXR5X3JhdGUgPC0gKG92ZXJhbGxfcG9zaXRpdmVfY291bnQgLyBvdmVyYWxsX3RvdGFsX2NvdW50KSAqIDEwMCAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKb3ZlcmFsbF9yb3cgPC0gZGF0YS5mcmFtZSgKICBTdGFnZSA9ICJPdmVyYWxsIiwKICBUb3RhbF9Db3VudCA9IG92ZXJhbGxfdG90YWxfY291bnQsCiAgUG9zaXRpdmVfQ291bnQgPSBvdmVyYWxsX3Bvc2l0aXZlX2NvdW50LAogIFJhdGUgPSBzcHJpbnRmKCIlLjJmJSUiLCBvdmVyYWxsX3Bvc2l0aXZpdHlfcmF0ZSkKKQpjb21iaW5lZF9kYXRhIDwtIHJiaW5kKGNvbWJpbmVkX2RhdGEsIG92ZXJhbGxfcm93KQpwcmludChjb21iaW5lZF9kYXRhKQoKI2N0RE5BIGF0IE1SRCBXaW5kb3cKcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSRjdEROQS5NUkQgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5NUkQsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNpcmNfZGF0YSRTdGFnZSA8LSBmYWN0b3IoY2lyY19kYXRhJFN0YWdlLCBsZXZlbHM9YygiSUkiLCAiSUlJIikpCnBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSA8LSBhZ2dyZWdhdGUoY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiLCBieT1saXN0KGNpcmNfZGF0YSRTdGFnZSksIEZVTj1zdW0pCnRvdGFsX2NvdW50c19ieV9zdGFnZSA8LSBhZ2dyZWdhdGUoY2lyY19kYXRhJGN0RE5BLk1SRCwgYnk9bGlzdChjaXJjX2RhdGEkU3RhZ2UpLCBGVU49bGVuZ3RoKQpjb21iaW5lZF9kYXRhIDwtIGRhdGEuZnJhbWUoCiAgU3RhZ2UgPSB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkR3JvdXAuMSwKICBUb3RhbF9Db3VudCA9IHRvdGFsX2NvdW50c19ieV9zdGFnZSR4LAogIFBvc2l0aXZlX0NvdW50ID0gcG9zaXRpdmVfY291bnRzX2J5X3N0YWdlJHgsCiAgUmF0ZSA9IChwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UkeCAvIHRvdGFsX2NvdW50c19ieV9zdGFnZSR4KSAqIDEwMCAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKKQpjb21iaW5lZF9kYXRhJFJhdGUgPC0gc3ByaW50ZigiJS4yZiUlIiwgY29tYmluZWRfZGF0YSRSYXRlKQpvdmVyYWxsX3RvdGFsX2NvdW50IDwtIG5yb3coY2lyY19kYXRhKQpvdmVyYWxsX3Bvc2l0aXZlX2NvdW50IDwtIG5yb3coY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIixdKQpvdmVyYWxsX3Bvc2l0aXZpdHlfcmF0ZSA8LSAob3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCAvIG92ZXJhbGxfdG90YWxfY291bnQpICogMTAwICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQpvdmVyYWxsX3JvdyA8LSBkYXRhLmZyYW1lKAogIFN0YWdlID0gIk92ZXJhbGwiLAogIFRvdGFsX0NvdW50ID0gb3ZlcmFsbF90b3RhbF9jb3VudCwKICBQb3NpdGl2ZV9Db3VudCA9IG92ZXJhbGxfcG9zaXRpdmVfY291bnQsCiAgUmF0ZSA9IHNwcmludGYoIiUuMmYlJSIsIG92ZXJhbGxfcG9zaXRpdml0eV9yYXRlKQopCmNvbWJpbmVkX2RhdGEgPC0gcmJpbmQoY29tYmluZWRfZGF0YSwgb3ZlcmFsbF9yb3cpCnByaW50KGNvbWJpbmVkX2RhdGEpCgojY3RETkEgYXQgU3VydmVpbGxhbmNlIFdpbmRvdwpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjaXJjX2RhdGEgPC0gc3Vic2V0KGNpcmNfZGF0YSwgY3RETkEuU3VydmVpbGxhbmNlICVpbiUgYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSkKY2lyY19kYXRhJFN0YWdlIDwtIGZhY3RvcihjaXJjX2RhdGEkU3RhZ2UsIGxldmVscz1jKCJJSSIsICJJSUkiKSkKcG9zaXRpdmVfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlID09ICJQT1NJVElWRSIsIGJ5PWxpc3QoY2lyY19kYXRhJFN0YWdlKSwgRlVOPXN1bSkKdG90YWxfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlLCBieT1saXN0KGNpcmNfZGF0YSRTdGFnZSksIEZVTj1sZW5ndGgpCmNvbWJpbmVkX2RhdGEgPC0gZGF0YS5mcmFtZSgKICBTdGFnZSA9IHRvdGFsX2NvdW50c19ieV9zdGFnZSRHcm91cC4xLAogIFRvdGFsX0NvdW50ID0gdG90YWxfY291bnRzX2J5X3N0YWdlJHgsCiAgUG9zaXRpdmVfQ291bnQgPSBwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UkeCwKICBSYXRlID0gKHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4IC8gdG90YWxfY291bnRzX2J5X3N0YWdlJHgpICogMTAwICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQopCmNvbWJpbmVkX2RhdGEkUmF0ZSA8LSBzcHJpbnRmKCIlLjJmJSUiLCBjb21iaW5lZF9kYXRhJFJhdGUpCm92ZXJhbGxfdG90YWxfY291bnQgPC0gbnJvdyhjaXJjX2RhdGEpCm92ZXJhbGxfcG9zaXRpdmVfY291bnQgPC0gbnJvdyhjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSA9PSAiUE9TSVRJVkUiLF0pCm92ZXJhbGxfcG9zaXRpdml0eV9yYXRlIDwtIChvdmVyYWxsX3Bvc2l0aXZlX2NvdW50IC8gb3ZlcmFsbF90b3RhbF9jb3VudCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCm92ZXJhbGxfcm93IDwtIGRhdGEuZnJhbWUoCiAgU3RhZ2UgPSAiT3ZlcmFsbCIsCiAgVG90YWxfQ291bnQgPSBvdmVyYWxsX3RvdGFsX2NvdW50LAogIFBvc2l0aXZlX0NvdW50ID0gb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCwKICBSYXRlID0gc3ByaW50ZigiJS4yZiUlIiwgb3ZlcmFsbF9wb3NpdGl2aXR5X3JhdGUpCikKY29tYmluZWRfZGF0YSA8LSByYmluZChjb21iaW5lZF9kYXRhLCBvdmVyYWxsX3JvdykKcHJpbnQoY29tYmluZWRfZGF0YSkKYGBgCgoKCiNjdEROQSBNUkQgRGV0ZWN0aW9uIHJhdGUgU3RhZ2UgSUkgdnMgSUlJCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEkY3RETkEuTVJEIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuTVJELCBsZXZlbHMgPSBjKCJORUdBVElWRSIsICJQT1NJVElWRSIpKQpjaXJjX2RhdGEkU3RhZ2VfR3JvdXBlZCA8LSBmYWN0b3IoaWZlbHNlKGNpcmNfZGF0YSRTdGFnZSAlaW4lIGMoIklJIiwgIklJIiksICJJSSIsICJJSUkiKSkKY29udGluZ2VuY3lfdGFibGUgPC0gdGFibGUoY2lyY19kYXRhJFN0YWdlX0dyb3VwZWQsIGNpcmNfZGF0YSRjdEROQS5NUkQpCmNoaV9zcXVhcmVfdGVzdCA8LSBjaGlzcS50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChjb250aW5nZW5jeV90YWJsZSkKcHJpbnQoY2hpX3NxdWFyZV90ZXN0KQpgYGAKCiNjdEROQSBTdXJ2ZWlsbGFuY2UgRGV0ZWN0aW9uIHJhdGUgU3RhZ2UgSUkgdnMgSUlJCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlLCBsZXZlbHMgPSBjKCJORUdBVElWRSIsICJQT1NJVElWRSIpKQpjaXJjX2RhdGEkU3RhZ2VfR3JvdXBlZCA8LSBmYWN0b3IoaWZlbHNlKGNpcmNfZGF0YSRTdGFnZSAlaW4lIGMoIklJIiwgIklJIiksICJJSSIsICJJSUkiKSkKY29udGluZ2VuY3lfdGFibGUgPC0gdGFibGUoY2lyY19kYXRhJFN0YWdlX0dyb3VwZWQsIGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UpCmNoaV9zcXVhcmVfdGVzdCA8LSBjaGlzcS50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChjb250aW5nZW5jeV90YWJsZSkKcHJpbnQoY2hpX3NxdWFyZV90ZXN0KQpgYGAKCiNjdEROQSB0aW1lcG9pbnRzIGNhZGVuY2UgYXQgdGhlIE1SRCBXaW5kb3cKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikgCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQoKY2lyY19kYXRhJE1SRF9UaW1lX3dlZWtzIDwtIGNpcmNfZGF0YSRjdEROQS5NUkQuVGltZSAvIDcKCiMgUGxvdCB0aGUgaGlzdG9ncmFtCmhpc3QoY2lyY19kYXRhJE1SRF9UaW1lX3dlZWtzLAogICAgIGNvbCA9ICdncmF5JywKICAgICBtYWluID0gJ1N1cmdlcnkgdG8gZmlyc3QgY3RETkEgdGVzdGluZyBhdCBNUkQgd2luZG93JywKICAgICB4bGFiID0gJ1dlZWtzIGZyb20gc3VyZ2VyeSB0byBmaXJzdCBjdEROQSB0ZXN0IGF0IE1SRCB3aW5kb3cnLAogICAgIHlsYWIgPSAnY3RETkEgU2FtcGxlcycsCiAgICAgeWxpbSA9IGMoMCwgMTIwKSwKICAgICB4bGltID0gYygwLCAxMCksCiAgICAgYnJlYWtzID0gc2VxKDAsIDI0LCAxKSwKICAgICB4YXhwID0gYygwLCAyNCwgMjQpKQpgYGAKCiNERlMgYnkgY3RETkEgYXQgdGhlIE1SRCBXaW5kb3cgLSBBbGwgc3RhZ2VzIExhbmRtYXJrIE1SRCB0aW1lcG9pbnQKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuTVJELm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+Y3RETkEuTVJELCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5NUkQpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLk1SRCwgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIsInJlZCIpLCB0aXRsZT0iREZTIC0gY3RETkEgTVJEIHdpbmRvdyB8IEFsbCBzdGFnZXMiLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJjdEROQSBOZWdhdGl2ZSIsICJjdEROQSBQb3NpdGl2ZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDEyLCAxOCwgMjQpKQpjaXJjX2RhdGEkY3RETkEuTVJEIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuTVJELCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuTVJELCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgojRmlzaGVyIHRlc3QgZm9yIERGUyBwZXJjZW50YWdlcyBhdCAxMiwgMTgsIGFuZCAyNCBtb250aHMKZGZzX3RpbWVzIDwtIGMoMTIsIDE4LCAyNCkKcF92YWx1ZXMgPC0gc2FwcGx5KGRmc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgcG9zX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBuZWdfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5FR0FUSVZFIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzIDwgdGltZSkKICAKICBzdXJ2X21hdHJpeCA8LSBtYXRyaXgoYyhuZWdfc3VydiwgcG9zX3N1cnYsIG5lZ190b3RhbCAtIG5lZ19zdXJ2LCBwb3NfdG90YWwgLSBwb3Nfc3VydiksIG5yb3cgPSAyKQogIHRlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KHN1cnZfbWF0cml4KQogIHJldHVybih0ZXN0X3Jlc3VsdCRwLnZhbHVlKQp9KQpuYW1lcyhwX3ZhbHVlcykgPC0gcGFzdGUwKCJwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKYGBgCgoKCgojTXVsdGl2YXJpYXRlIGNveCByZWdyZXNzaW9uIGF0IE1SRCBXaW5kb3cgZm9yIERGUyAtIEFsbCBzdGFnZXMgTGFuZG1hcmsgTVJEIHRpbWVwb2ludApgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5NUkQubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkY3RETkEuTVJEIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuTVJELCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpLCBsYWJlbHMgPSBjKCJOZWdhdGl2ZSIsICJQb3NpdGl2ZSIpKQpjaXJjX2RhdGEkR2VuZGVyIDwtIGZhY3RvcihjaXJjX2RhdGEkR2VuZGVyLCBsZXZlbHMgPSBjKCJGZW1hbGUiLCAiTWFsZSIpKQpjaXJjX2RhdGEkQWdlLkdyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkQWdlLkdyb3VwLCBsZXZlbHMgPSBjKCIxIiwgIjIiKSwgbGFiZWxzID0gYygiPDcwIiwgIj43MCIpKQpjaXJjX2RhdGEkRUNPRyA8LSBmYWN0b3IoY2lyY19kYXRhJEVDT0csIGxldmVscyA9IGMoIjAiLCAiMSIpKQpjaXJjX2RhdGEkcFQgPC0gZmFjdG9yKGNpcmNfZGF0YSRwVCwgbGV2ZWxzID0gYygiVDEtVDIiLCAiVDMtVDQiKSkKY2lyY19kYXRhJHBOIDwtIGZhY3RvcihjaXJjX2RhdGEkcE4sIGxldmVscyA9IGMoIk4wIiwgIk4xLU4yIikpCmNpcmNfZGF0YSRSQVMgPC0gZmFjdG9yKGNpcmNfZGF0YSRSQVMsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJXaWxkLVR5cGUiLCAiTXV0YW50IikpCnN1cnZfb2JqZWN0IDwtIFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KSAKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLk1SRCArIEdlbmRlciArIEFnZS5Hcm91cCArIEVDT0cgKyBwVCArIHBOICsgUkFTLCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsIGRhdGEgPSBjaXJjX2RhdGEsIG1haW4gPSAiTXVsdGl2YXJpYXRlIFJlZ3Jlc3Npb24gTW9kZWwgZm9yIERGUyAtIEFsbCBTdGFnZXMiLCByZWZMYWJlbCA9ICJSZWZlcmVuY2UgR3JvdXAiKQp0ZXN0LnBoIDwtIGNveC56cGgoY294X2ZpdCkKYGBgCgoKI0RGUyBieSBjdEROQSBhdCB0aGUgTVJEIFdpbmRvdyAtIFN0YWdlIElJIExhbmRtYXJrIE1SRCB0aW1lcG9pbnQKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhWyEoY2lyY19kYXRhJFN0YWdlICVpbiUgYygiSUlJIikpLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLk1SRC5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpfmN0RE5BLk1SRCwgZGF0YSA9IGNpcmNfZGF0YSkKZXZlbnRfc3VtbWFyeSA8LSBjaXJjX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY3RETkEuTVJEKSAlPiUKICBzdW1tYXJpc2UoCiAgICBUb3RhbCA9IG4oKSwKICAgIEV2ZW50cyA9IHN1bShERlMuRXZlbnQpLAogICAgRnJhY3Rpb24gPSBFdmVudHMgLyBuKCksCiAgICBQZXJjZW50YWdlID0gKEV2ZW50cyAvIG4oKSkgKiAxMDAKICApCnByaW50KGV2ZW50X3N1bW1hcnkpCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBjdEROQS5NUkQsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIE1SRCB3aW5kb3cgfCBTdGFnZSBJSSIsIHlsYWI9ICJEaXNlYXNlLUZyZWUgU3Vydml2YWwiLCB4bGFiPSJUaW1lIGZyb20gTGFuZG1hcmsgVGltZSBwb2ludCAoTW9udGhzKSIsIGxlZ2VuZC5sYWJzPWMoImN0RE5BIE5lZ2F0aXZlIiwgImN0RE5BIFBvc2l0aXZlIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDI0KSkKY2lyY19kYXRhJGN0RE5BLk1SRCA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLk1SRCwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLk1SRCwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKI0Zpc2hlciB0ZXN0IGZvciBERlMgcGVyY2VudGFnZXMgYXQgMTIgYW5kIDI0IG1vbnRocwpkZnNfdGltZXMgPC0gYygxMiwgMjQpCnBfdmFsdWVzIDwtIHNhcHBseShkZnNfdGltZXMsIGZ1bmN0aW9uKHRpbWUpIHsKICBuZWdfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIHBvc19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJORUdBVElWRSIpCiAgcG9zX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIpCiAgCiAgbmVnX3N1cnYgPC0gbmVnX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA8IHRpbWUpCiAgcG9zX3N1cnYgPC0gcG9zX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXMpCmBgYAoKI0RGUyBieSBjdEROQSBhdCB0aGUgTVJEIFdpbmRvdyAtIFN0YWdlIElJSSBMYW5kbWFyayBNUkQgdGltZXBvaW50CmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRFbGlnaWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbIShjaXJjX2RhdGEkU3RhZ2UgJWluJSBjKCJJSSIpKSxdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5NUkQubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5jdEROQS5NUkQsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KGN0RE5BLk1SRCkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuTVJELCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiwicmVkIiksIHRpdGxlPSJERlMgLSBjdEROQSBNUkQgd2luZG93IHwgU3RhZ2UgSUlJIiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiY3RETkEgTmVnYXRpdmUiLCAiY3RETkEgUG9zaXRpdmUiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygyNCwgMzApKQpjaXJjX2RhdGEkY3RETkEuTVJEIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuTVJELCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuTVJELCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgojRmlzaGVyIHRlc3QgZm9yIERGUyBwZXJjZW50YWdlcyBhdCAyNCBhbmQgMzAgbW9udGhzCmRmc190aW1lcyA8LSBjKDI0LCAzMCkKY2lyY19kYXRhIDwtIG5hLm9taXQoY2lyY19kYXRhWywgYygiY3RETkEuTVJEIiwgIkRGUy5NUkQubW9udGhzIiwgIkRGUy5FdmVudCIpXSkKcF92YWx1ZXMgPC0gc2FwcGx5KGRmc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgcG9zX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBuZWdfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5FR0FUSVZFIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzIDwgdGltZSkKICAKICBzdXJ2X21hdHJpeCA8LSBtYXRyaXgoYyhuZWdfc3VydiwgcG9zX3N1cnYsIG5lZ190b3RhbCAtIG5lZ19zdXJ2LCBwb3NfdG90YWwgLSBwb3Nfc3VydiksIG5yb3cgPSAyKQogIHRlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KHN1cnZfbWF0cml4KQogIHJldHVybih0ZXN0X3Jlc3VsdCRwLnZhbHVlKQp9KQpuYW1lcyhwX3ZhbHVlcykgPC0gcGFzdGUwKCJwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKYGBgCgoKCgoKCiNERlMgYnkgY3RETkEgYXQgdGhlIE1SRCBXaW5kb3cgLSAyLTQgd2Vla3MgcG9zdC1zdXJnZXJ5CmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLk1SRC5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRNUkRfVGltZV93ZWVrcyA8LSBjaXJjX2RhdGEkY3RETkEuTVJELlRpbWUgLyA3CmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJE1SRF9UaW1lX3dlZWtzIDwgNCwgXQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+Y3RETkEuTVJELCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5NUkQpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLk1SRCwgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIsInJlZCIpLCB0aXRsZT0iREZTIC0gY3RETkEgTVJEIHdpbmRvdyB8IDItNCB3ZWVrcyIsIHlsYWI9ICJEaXNlYXNlLUZyZWUgU3Vydml2YWwiLCB4bGFiPSJUaW1lIGZyb20gTGFuZG1hcmsgVGltZSBwb2ludCAoTW9udGhzKSIsIGxlZ2VuZC5sYWJzPWMoImN0RE5BIE5lZ2F0aXZlIiwgImN0RE5BIFBvc2l0aXZlIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDE4LCAyNCkpCmNpcmNfZGF0YSRjdEROQS5NUkQgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5NUkQsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBjdEROQS5NUkQsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCiNGaXNoZXIgdGVzdCBmb3IgREZTIHBlcmNlbnRhZ2VzIGF0IDEyLCAxOCBhbmQgMjQgbW9udGhzCmRmc190aW1lcyA8LSBjKDEyLCAxOCwgMjQpCmNpcmNfZGF0YSA8LSBuYS5vbWl0KGNpcmNfZGF0YVssIGMoImN0RE5BLk1SRCIsICJERlMuTVJELm1vbnRocyIsICJERlMuRXZlbnQiKV0pCnBfdmFsdWVzIDwtIHNhcHBseShkZnNfdGltZXMsIGZ1bmN0aW9uKHRpbWUpIHsKICBuZWdfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIHBvc19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJORUdBVElWRSIpCiAgcG9zX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIpCiAgCiAgbmVnX3N1cnYgPC0gbmVnX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA8IHRpbWUpCiAgcG9zX3N1cnYgPC0gcG9zX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXMpCmBgYAoKI0RGUyBieSBjdEROQSBhdCB0aGUgTVJEIFdpbmRvdyAtIDQtMTAgd2Vla3MgcG9zdC1zdXJnZXJ5CmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLk1SRC5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRNUkRfVGltZV93ZWVrcyA8LSBjaXJjX2RhdGEkY3RETkEuTVJELlRpbWUgLyA3CmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJE1SRF9UaW1lX3dlZWtzID4gNCwgXQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+Y3RETkEuTVJELCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5NUkQpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLk1SRCwgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIsInJlZCIpLCB0aXRsZT0iREZTIC0gY3RETkEgTVJEIHdpbmRvdyB8IDQtMTAgd2Vla3MiLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJjdEROQSBOZWdhdGl2ZSIsICJjdEROQSBQb3NpdGl2ZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDEyLCAxOCwgMjQpKQpjaXJjX2RhdGEkY3RETkEuTVJEIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuTVJELCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuTVJELCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgojRmlzaGVyIHRlc3QgZm9yIERGUyBwZXJjZW50YWdlcyBhdCAxMiwgMTggYW5kIDI0IG1vbnRocwpkZnNfdGltZXMgPC0gYygxMiwgMTgsIDI0KQpjaXJjX2RhdGEgPC0gbmEub21pdChjaXJjX2RhdGFbLCBjKCJjdEROQS5NUkQiLCAiREZTLk1SRC5tb250aHMiLCAiREZTLkV2ZW50IildKQpwX3ZhbHVlcyA8LSBzYXBwbHkoZGZzX3RpbWVzLCBmdW5jdGlvbih0aW1lKSB7CiAgbmVnX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIG5lZ190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiKQogIAogIG5lZ19zdXJ2IDwtIG5lZ190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPCB0aW1lKQogIHBvc19zdXJ2IDwtIHBvc190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPCB0aW1lKQogIAogIHN1cnZfbWF0cml4IDwtIG1hdHJpeChjKG5lZ19zdXJ2LCBwb3Nfc3VydiwgbmVnX3RvdGFsIC0gbmVnX3N1cnYsIHBvc190b3RhbCAtIHBvc19zdXJ2KSwgbnJvdyA9IDIpCiAgdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3Qoc3Vydl9tYXRyaXgpCiAgcmV0dXJuKHRlc3RfcmVzdWx0JHAudmFsdWUpCn0pCm5hbWVzKHBfdmFsdWVzKSA8LSBwYXN0ZTAoInAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQpgYGAKCiNERlMgYnkgQUNUIHRyZWF0bWVudCBpbiBNUkQgbmVnYXRpdmUgLSBTdGFnZSBJSS9JSUkKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQ9PSJORUdBVElWRSIsXQpjaXJjX2RhdGEkREZTLm1vbnRocz1jaXJjX2RhdGEkREZTLm1vbnRocy0yCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+QUNULCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShBQ1QpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gQUNULCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJyZWQiLCJibHVlIiksIHRpdGxlPSJERlMgLSBjdEROQSBNUkQgTmVnYXRpdmUgQUNUIHZzIE9ic2VydmF0aW9uIHwgU3RhZ2UgSUkvSUlJIiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiT2JzZXJ2YXRpb24iLCAiQUNUIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMjQpKQpjaXJjX2RhdGEkQUNUIDwtIGZhY3RvcihjaXJjX2RhdGEkQUNULCBsZXZlbHM9YygiVFJVRSIsIkZBTFNFIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBBQ1QsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCiNGaXNoZXIgdGVzdCBmb3IgREZTIHBlcmNlbnRhZ2VzIGF0IDI0CmRmc190aW1lcyA8LSBjKDI0KQpwX3ZhbHVlcyA8LSBzYXBwbHkoZGZzX3RpbWVzLCBmdW5jdGlvbih0aW1lKSB7CiAgbmVnX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJUUlVFIiAmIGNpcmNfZGF0YSRERlMubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgcG9zX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJGQUxTRSIgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIG5lZ190b3RhbCA8LSBzdW0oY2lyY19kYXRhJEFDVCA9PSAiVFJVRSIpCiAgcG9zX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJGQUxTRSIpCiAgCiAgbmVnX3N1cnYgPC0gbmVnX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIlRSVUUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5tb250aHMgPCB0aW1lKQogIHBvc19zdXJ2IDwtIHBvc190b3RhbCAtIHN1bShjaXJjX2RhdGEkQUNUID09ICJGQUxTRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXMpCgojQWRqdXN0ZWQgSFIgIkFDVCB2cyBubyBBQ1QiIC0gTm9uIEFDVCBhcyByZWZlcmVuY2UKcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09Ik5FR0FUSVZFIixdCmNpcmNfZGF0YSRERlMubW9udGhzPWNpcmNfZGF0YSRERlMubW9udGhzLTIKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJEFDVCA8LSBmYWN0b3IoY2lyY19kYXRhJEFDVCwgbGV2ZWxzPWMoIkZBTFNFIiwiVFJVRSIpKQpjaXJjX2RhdGEkQWdlLkdyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkQWdlLkdyb3VwLCBsZXZlbHMgPSBjKCIxIiwgIjIiKSwgbGFiZWxzID0gYygiPDcwIiwgIuKJpTcwIikpCmNpcmNfZGF0YSRHZW5kZXIgPC0gZmFjdG9yKGNpcmNfZGF0YSRHZW5kZXIsIGxldmVscyA9IGMoIkZlbWFsZSIsICJNYWxlIikpCmNpcmNfZGF0YSRTdGFnZSA8LSBmYWN0b3IoY2lyY19kYXRhJFN0YWdlLCBsZXZlbHMgPSBjKCJJSSIsICJJSUkiKSkKY2lyY19kYXRhJEVDT0cgPC0gZmFjdG9yKGNpcmNfZGF0YSRFQ09HLCBsZXZlbHM9YygiMCIsIjEiKSkKc3Vydl9vYmplY3QgPC0gU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkgCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBBQ1QgKyBHZW5kZXIgKyBBZ2UuR3JvdXAgKyBTdGFnZSArIEVDT0csIGRhdGE9Y2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmBgYAoKCiNERlMgYnkgQUNUIHRyZWF0bWVudCBpbiBNUkQgcG9zaXRpdmUgLSBTdGFnZSBJSS9JSUkKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQ9PSJQT1NJVElWRSIsXQpjaXJjX2RhdGEkREZTLm1vbnRocz1jaXJjX2RhdGEkREZTLm1vbnRocy0yCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+QUNULCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShBQ1QpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gQUNULCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJyZWQiLCJibHVlIiksIHRpdGxlPSJERlMgLSBjdEROQSBNUkQgUG9zaXRpdmUgQUNUIHZzIE9ic2VydmF0aW9uIHwgU3RhZ2UgSUkvSUlJIiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiT2JzZXJ2YXRpb24iLCAiQUNUIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoNiwgMjQpKQpjaXJjX2RhdGEkQUNUIDwtIGZhY3RvcihjaXJjX2RhdGEkQUNULCBsZXZlbHM9YygiVFJVRSIsIkZBTFNFIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBBQ1QsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCiNBZGp1c3RlZCBIUiAiQUNUIHZzIG5vIEFDVCIgLSBOb24gQUNUIGFzIHJlZmVyZW5jZQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEPT0iUE9TSVRJVkUiLF0KY2lyY19kYXRhJERGUy5tb250aHM9Y2lyY19kYXRhJERGUy5tb250aHMtMgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkQUNUIDwtIGZhY3RvcihjaXJjX2RhdGEkQUNULCBsZXZlbHM9YygiRkFMU0UiLCJUUlVFIikpCmNpcmNfZGF0YSRBZ2UuR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRBZ2UuR3JvdXAsIGxldmVscyA9IGMoIjEiLCAiMiIpLCBsYWJlbHMgPSBjKCI8NzAiLCAi4omlNzAiKSkKY2lyY19kYXRhJEdlbmRlciA8LSBmYWN0b3IoY2lyY19kYXRhJEdlbmRlciwgbGV2ZWxzID0gYygiRmVtYWxlIiwgIk1hbGUiKSkKY2lyY19kYXRhJFN0YWdlIDwtIGZhY3RvcihjaXJjX2RhdGEkU3RhZ2UsIGxldmVscyA9IGMoIklJIiwgIklJSSIpKQpjaXJjX2RhdGEkRUNPRyA8LSBmYWN0b3IoY2lyY19kYXRhJEVDT0csIGxldmVscz1jKCIwIiwiMSIpKQpzdXJ2X29iamVjdCA8LSBTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KSAKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IEFDVCArIEdlbmRlciArIEFnZS5Hcm91cCArIFN0YWdlICsgRUNPRywgZGF0YT1jaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKYGBgCgoKI0RGUyBieSBjdEROQSBhdCAzIG1vbnRocyAtIEFsbCBzdGFnZXMgTGFuZG1hcmsgMyBtb250aHMgdGltZXBvaW50CmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS4zbW9udGhzIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy4zbW8ubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuM21vLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5jdEROQS4zbW9udGhzLCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS4zbW9udGhzKSAlPiUKICBzdW1tYXJpc2UoCiAgICBUb3RhbCA9IG4oKSwKICAgIEV2ZW50cyA9IHN1bShERlMuRXZlbnQpLAogICAgRnJhY3Rpb24gPSBFdmVudHMgLyBuKCksCiAgICBQZXJjZW50YWdlID0gKEV2ZW50cyAvIG4oKSkgKiAxMDAKICApCnByaW50KGV2ZW50X3N1bW1hcnkpCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy4zbW8ubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBjdEROQS4zbW9udGhzLCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiwicmVkIiksIHRpdGxlPSJERlMgLSBjdEROQSAzIG1vbnRocyB8IEFsbCBzdGFnZXMiLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJjdEROQSBOZWdhdGl2ZSIsICJjdEROQSBQb3NpdGl2ZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDEyLCAyNCkpCmNpcmNfZGF0YSRjdEROQS4zbW9udGhzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuM21vbnRocywgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLjNtb250aHMsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCiNGaXNoZXIgdGVzdCBmb3IgREZTIHBlcmNlbnRhZ2VzIGF0IDEyIGFuZCAyNCBtb250aHMKZGZzX3RpbWVzIDwtIGMoMTIsIDI0KQpwX3ZhbHVlcyA8LSBzYXBwbHkoZGZzX3RpbWVzLCBmdW5jdGlvbih0aW1lKSB7CiAgbmVnX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuM21vbnRocyA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy4zbW8ubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgcG9zX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuM21vbnRocyA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy4zbW8ubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuM21vbnRocyA9PSAiTkVHQVRJVkUiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLjNtb250aHMgPT0gIlBPU0lUSVZFIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLjNtb250aHMgPT0gIk5FR0FUSVZFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuM21vLm1vbnRocyA8IHRpbWUpCiAgcG9zX3N1cnYgPC0gcG9zX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS4zbW9udGhzID09ICJQT1NJVElWRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLjNtby5tb250aHMgPCB0aW1lKQogIAogIHN1cnZfbWF0cml4IDwtIG1hdHJpeChjKG5lZ19zdXJ2LCBwb3Nfc3VydiwgbmVnX3RvdGFsIC0gbmVnX3N1cnYsIHBvc190b3RhbCAtIHBvc19zdXJ2KSwgbnJvdyA9IDIpCiAgdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3Qoc3Vydl9tYXRyaXgpCiAgcmV0dXJuKHRlc3RfcmVzdWx0JHAudmFsdWUpCn0pCm5hbWVzKHBfdmFsdWVzKSA8LSBwYXN0ZTAoInAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQpgYGAKCgoKCiNERlMgYnkgY3RETkEgYXQgNiBtb250aHMgLSBBbGwgc3RhZ2VzIExhbmRtYXJrIDYgbW9udGhzIHRpbWVwb2ludApgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuNm1vbnRocyE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuNm1vLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLjZtby5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+Y3RETkEuNm1vbnRocywgZGF0YSA9IGNpcmNfZGF0YSkKZXZlbnRfc3VtbWFyeSA8LSBjaXJjX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY3RETkEuNm1vbnRocykgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuNm1vLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuNm1vbnRocywgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIsInJlZCIpLCB0aXRsZT0iREZTIC0gY3RETkEgNiBtb250aHMgfCBBbGwgc3RhZ2VzIiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiY3RETkEgTmVnYXRpdmUiLCAiY3RETkEgUG9zaXRpdmUiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYyg2LCAyNCkpCmNpcmNfZGF0YSRjdEROQS42bW9udGhzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuNm1vbnRocywgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLjZtb250aHMsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCiNGaXNoZXIgdGVzdCBmb3IgREZTIHBlcmNlbnRhZ2VzIGF0IDYgYW5kIDI0IG1vbnRocwpkZnNfdGltZXMgPC0gYyg2LCAyNCkKcF92YWx1ZXMgPC0gc2FwcGx5KGRmc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLjZtb250aHMgPT0gIk5FR0FUSVZFIiAmIGNpcmNfZGF0YSRERlMuNm1vLm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIHBvc19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLjZtb250aHMgPT0gIlBPU0lUSVZFIiAmIGNpcmNfZGF0YSRERlMuNm1vLm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIG5lZ190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLjZtb250aHMgPT0gIk5FR0FUSVZFIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS42bW9udGhzID09ICJQT1NJVElWRSIpCiAgCiAgbmVnX3N1cnYgPC0gbmVnX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS42bW9udGhzID09ICJORUdBVElWRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLjZtby5tb250aHMgPCB0aW1lKQogIHBvc19zdXJ2IDwtIHBvc190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuNm1vbnRocyA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy42bW8ubW9udGhzIDwgdGltZSkKICAKICBzdXJ2X21hdHJpeCA8LSBtYXRyaXgoYyhuZWdfc3VydiwgcG9zX3N1cnYsIG5lZ190b3RhbCAtIG5lZ19zdXJ2LCBwb3NfdG90YWwgLSBwb3Nfc3VydiksIG5yb3cgPSAyKQogIHRlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KHN1cnZfbWF0cml4KQogIHJldHVybih0ZXN0X3Jlc3VsdCRwLnZhbHVlKQp9KQpuYW1lcyhwX3ZhbHVlcykgPC0gcGFzdGUwKCJwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKYGBgCgoKCgojREZTIGJ5IGN0RE5BIENsZWFyYW5jZSBBQ1QtdHJlYXRlZCBhdCAzIG1vbnRocyAtIGFsbCBzdGFnZXMKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXSAKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQUNUPT1UUlVFLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gTkEgI2ZpcnN0IHdlIGNyZWF0ZSB0aGUgdmFyaWFibGUgZm9yIHRoZSBjdEROQSAmIE5BQyBjb21iaW5hdGlvbiwgYW5kIHdlIGFzc2lnbiB2YWx1ZXMKY2lyY19kYXRhIDwtIGNpcmNfZGF0YSAlPiUKICBtdXRhdGUoY3RETkEuRHluYW1pY3MgPSBjYXNlX3doZW4oCiAgICBjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLjNtb250aHMgPT0gIk5FR0FUSVZFIiB+IDEsCiAgICBjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLjNtb250aHMgPT0gIlBPU0lUSVZFIiB+IDIKICApKQoKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLjNtby5tb250aHM+PTAsXQpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuM21vLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5jdEROQS5EeW5hbWljcywgZGF0YSA9IGNpcmNfZGF0YSkKZXZlbnRfc3VtbWFyeSA8LSBjaXJjX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY3RETkEuRHluYW1pY3MpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLjNtby5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiwicmVkIiksIHRpdGxlPSJERlMgLSBjdEROQSBDbGVhcmFuY2UgZnJvbSBNUkQgdG8gMyBtb250aHMgQUNULXRyZWF0ZWQgfCBBbGwgU3RhZ2VzIiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiQ2xlYXJhbmNlIiwgIk5vIENsZWFyYW5jZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDEyLCAyNCkpCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzLCBsZXZlbHM9YygiMSIsIjIiKSwgbGFiZWxzID0gYygiQ2xlYXJhbmNlIiwgIk5vIENsZWFyYW5jZSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgojRmlzaGVyIHRlc3QgZm9yIERGUyBwZXJjZW50YWdlcyBhdCAxMiBhbmQgMjQgbW9udGhzCmRmc190aW1lcyA8LSBjKDEyKQpjaXJjX2RhdGEgPC0gbmEub21pdChjaXJjX2RhdGFbLCBjKCJjdEROQS5EeW5hbWljcyIsICJERlMuM21vLm1vbnRocyIsICJERlMuRXZlbnQiKV0pCnBfdmFsdWVzIDwtIHNhcHBseShkZnNfdGltZXMsIGZ1bmN0aW9uKHRpbWUpIHsKICBuZWdfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiQ2xlYXJhbmNlIiAmIGNpcmNfZGF0YSRERlMuM21vLm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSBGQUxTRSkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiTm8gQ2xlYXJhbmNlIiAmIGNpcmNfZGF0YSRERlMuM21vLm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSBGQUxTRSkKICBuZWdfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiQ2xlYXJhbmNlIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiTm8gQ2xlYXJhbmNlIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJDbGVhcmFuY2UiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSBUUlVFICYgY2lyY19kYXRhJERGUy4zbW8ubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJObyBDbGVhcmFuY2UiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSBUUlVFICYgY2lyY19kYXRhJERGUy4zbW8ubW9udGhzIDwgdGltZSkKICAKICBzdXJ2X21hdHJpeCA8LSBtYXRyaXgoYyhuZWdfc3VydiwgcG9zX3N1cnYsIG5lZ190b3RhbCAtIG5lZ19zdXJ2LCBwb3NfdG90YWwgLSBwb3Nfc3VydiksIG5yb3cgPSAyKQogIHRlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KHN1cnZfbWF0cml4KQogIHJldHVybih0ZXN0X3Jlc3VsdCRwLnZhbHVlKQp9KQpuYW1lcyhwX3ZhbHVlcykgPC0gcGFzdGUwKCJwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKYGBgCgoKI0RGUyBieSBjdEROQSBDbGVhcmFuY2UgQUNULXRyZWF0ZWQgYXQgNiBtb250aHMgLSBhbGwgc3RhZ2VzCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQUNUPT1UUlVFLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gTkEgI2ZpcnN0IHdlIGNyZWF0ZSB0aGUgdmFyaWFibGUgZm9yIHRoZSBjdEROQSAmIE5BQyBjb21iaW5hdGlvbiwgYW5kIHdlIGFzc2lnbiB2YWx1ZXMKY2lyY19kYXRhIDwtIGNpcmNfZGF0YSAlPiUKICBtdXRhdGUoY3RETkEuRHluYW1pY3MgPSBjYXNlX3doZW4oCiAgICBjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLjZtb250aHMgPT0gIk5FR0FUSVZFIiB+IDEsCiAgICBjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLjZtb250aHMgPT0gIlBPU0lUSVZFIiB+IDIKICApKQoKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLjZtby5tb250aHM+PTAsXQpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuNm1vLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5jdEROQS5EeW5hbWljcywgZGF0YSA9IGNpcmNfZGF0YSkKZXZlbnRfc3VtbWFyeSA8LSBjaXJjX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY3RETkEuRHluYW1pY3MpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLjZtby5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiwicmVkIiksIHRpdGxlPSJERlMgLSBjdEROQSBDbGVhcmFuY2UgZnJvbSBNUkQgdG8gNiBtb250aHMgQUNULXRyZWF0ZWQgfCBBbGwgU3RhZ2VzIiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiQ2xlYXJhbmNlIiwgIk5vIENsZWFyYW5jZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDEyLCAyNCkpCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzLCBsZXZlbHM9YygiMSIsIjIiKSwgbGFiZWxzID0gYygiQ2xlYXJhbmNlIiwgIk5vIENsZWFyYW5jZSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCmBgYAoKCiNQZXJjZW50YWdlcyBvZiBNUkQgbmVnYXRpdmUgd2l0aCBtb2xlY3VsYXIgcmVjdXJyZW5jZSAocmV0dXJuZWQgcG9zaXRpdmUpIHBvc3QtTVJECmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQgIT0gIiIgJiBjaXJjX2RhdGEkTGVhZC5UaW1lID49IDAsIF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEPT0iTkVHQVRJVkUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkUG9zdE1SRFBvcy5FdmVudD09IlRSVUUiLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgojIENvbnZlcnQgZGF5cyB0byBtb250aHMKY2lyY19kYXRhJFBvc3RNUkRQb3MubW9udGhzIDwtIGNpcmNfZGF0YSRQb3N0TVJEUG9zLzMwLjQzNwoKIyBEZWZpbmUgdGhlIGludGVydmFsczogMC02LCA2LTksIDktMTIsIDEyLTE1LCAxNS0xOCwgMTgtMjEsIDIxLTI0LCA+MjQgbW9udGhzCmJyZWFrcyA8LSBjKDAsIDYsIDksIDEyLCAxNSwgMTgsIDIxLCAyNCwgNDgpCmxhYmVscyA8LSBjKCIwLTZtIiwgIjYtOW0iLCAiOS0xMm0iLCAiMTItMTVtIiwgIjE1LTE4bSIsICIxOC0yMW0iLCAiMjEtMjRtIiwgIj4yNG0iKQoKIyBDYXRlZ29yaXplIHBfZHJlbFJldHVybmVkX21vbnRocyBpbnRvIGludGVydmFscwpjaXJjX2RhdGEkcF9kcmVsUmV0dXJuZWRfaW50ZXJ2YWxzIDwtIGN1dChjaXJjX2RhdGEkUG9zdE1SRFBvcy5tb250aHMsIGJyZWFrcyA9IGJyZWFrcywgbGFiZWxzID0gbGFiZWxzLCByaWdodCA9IEZBTFNFKQoKIyBFeGFtaW5lIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGludGVydmFscwp0YWJsZShjaXJjX2RhdGEkcF9kcmVsUmV0dXJuZWRfaW50ZXJ2YWxzKQoKIyBHZXQgdGhlIGNvdW50cyBmb3IgZWFjaCBpbnRlcnZhbAppbnRlcnZhbF9jb3VudHMgPC0gdGFibGUoY2lyY19kYXRhJHBfZHJlbFJldHVybmVkX2ludGVydmFscykKCiMgQ2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlcwppbnRlcnZhbF9wZXJjZW50YWdlcyA8LSAxMDAgKiBpbnRlcnZhbF9jb3VudHMgLyBzdW0oaW50ZXJ2YWxfY291bnRzKQoKIyBDb21iaW5lIHRoZSBjb3VudHMgYW5kIHBlcmNlbnRhZ2VzIGZvciBhIGNsZWFyZXIgb3ZlcnZpZXcKaW50ZXJ2YWxfc3VtbWFyeSA8LSBkYXRhLmZyYW1lKENvdW50cyA9IGludGVydmFsX2NvdW50cywgUGVyY2VudGFnZXMgPSBpbnRlcnZhbF9wZXJjZW50YWdlcykKCiMgQ2FsY3VsYXRlIHRoZSB0b3RhbCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zCnRvdGFsX29ic2VydmF0aW9ucyA8LSBzdW0oaW50ZXJ2YWxfY291bnRzKQoKIyBBZGQgdGhlIHRvdGFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgdG8gdGhlIHN1bW1hcnkKaW50ZXJ2YWxfc3VtbWFyeSRUb3RhbE9ic2VydmF0aW9ucyA8LSBjKHJlcChOQSwgbGVuZ3RoKGludGVydmFsX2NvdW50cyktMSksIHRvdGFsX29ic2VydmF0aW9ucykKCiMgUHJpbnQgdGhlIHN1bW1hcnkgd2l0aCB0b3RhbCBvYnNlcnZhdGlvbnMKcHJpbnQoaW50ZXJ2YWxfc3VtbWFyeSkKCiMgQ2FsY3VsYXRlIGN1bXVsYXRpdmUgcGVyY2VudGFnZXMKY3VtdWxhdGl2ZV9wZXJjZW50YWdlcyA8LSBjdW1zdW0oaW50ZXJ2YWxfcGVyY2VudGFnZXMpCgojIENvbWJpbmUgdGhlIGNvdW50cywgcGVyY2VudGFnZXMsIGFuZCBjdW11bGF0aXZlIHBlcmNlbnRhZ2VzIGZvciBhIGNsZWFyZXIgb3ZlcnZpZXcKaW50ZXJ2YWxfc3VtbWFyeSA8LSBkYXRhLmZyYW1lKENvdW50cyA9IGludGVydmFsX2NvdW50cywgUGVyY2VudGFnZXMgPSBpbnRlcnZhbF9wZXJjZW50YWdlcywgQ3VtdWxhdGl2ZVBlcmNlbnRhZ2VzID0gY3VtdWxhdGl2ZV9wZXJjZW50YWdlcywgVG90YWxPYnNlcnZhdGlvbnMgPSBjKHJlcChOQSwgbGVuZ3RoKGludGVydmFsX2NvdW50cyktMSksIHRvdGFsX29ic2VydmF0aW9ucykpCgpicCA8LSBiYXJwbG90KGludGVydmFsX3BlcmNlbnRhZ2VzLCAKICAgICAgICAgICAgICBtYWluPSJNb2xlY3VsYXIgUmVjdXJyZW5jZSBwb3N0LU1SRCBpbiBNUkQgbmVnYXRpdmUgcGF0aWVudHMiLCAKICAgICAgICAgICAgICB4bGFiPSJNb250aHMgSW50ZXJ2YWwgZnJvbSBTdXJnZXJ5IiwgCiAgICAgICAgICAgICAgeWxhYj0iUGF0aWVudHMgJSBjb252ZXJ0ZWQgcG9zaXRpdmUiLCAKICAgICAgICAgICAgICBjb2w9ImxpZ2h0Ymx1ZSIsCiAgICAgICAgICAgICAgeWxpbT1jKDAsIDEwMCkpCgojIEFkZCB0aGUgY3VtdWxhdGl2ZSBwZXJjZW50YWdlcyB0byB0aGUgcGxvdApwb2ludHMoYnAsIGN1bXVsYXRpdmVfcGVyY2VudGFnZXMsIHR5cGU9Im8iLCBwY2g9MjIsIGNvbD0icmVkIiwgY2V4PTEuNSkKcHJpbnQoaW50ZXJ2YWxfc3VtbWFyeSkKYGBgCgoKCgojREZTIGJ5IGN0RE5BIE1SRCBwb3NpdGl2ZSB2cyBjdEROQSBuZWdhdGl2ZSB3aXRoIG1vbGVjdWxhciByZWN1cnJlbmNlIGF0IFN1cnZlaWxsYW5jZSAtIDMgZ3JvdXBzCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gTkEgI2ZpcnN0IHdlIGNyZWF0ZSB0aGUgdmFyaWFibGUgZm9yIHRoZSBjdEROQSAmIE5BQyBjb21iaW5hdGlvbiwgYW5kIHdlIGFzc2lnbiB2YWx1ZXMKY2lyY19kYXRhIDwtIGNpcmNfZGF0YSAlPiUKICBtdXRhdGUoY3RETkEuRHluYW1pY3MgPSBjYXNlX3doZW4oCiAgICBjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGN0RE5BLlN1cnZlaWxsYW5jZT09Ik5FR0FUSVZFIiB+IDEsCiAgICBjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGN0RE5BLlN1cnZlaWxsYW5jZT09IlBPU0lUSVZFIiB+IDIsCiAgICBjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiB+IDMKICApKQoKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLk1SRC5tb250aHM+PTAsXQpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5jdEROQS5EeW5hbWljcywgZGF0YSA9IGNpcmNfZGF0YSkKZXZlbnRfc3VtbWFyeSA8LSBjaXJjX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY3RETkEuRHluYW1pY3MpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiwiZ3JlZW4iLCJyZWQiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIE1SRCBQb3MgdnMgTmVnIHdpdGggTW9sZWN1bGFyIFJlY3VycmVuY2UgYXQgU3VydmVpbGxhbmNlIFdpbmRvdyIsIHlsYWI9ICJEaXNlYXNlLUZyZWUgU3Vydml2YWwiLCB4bGFiPSJUaW1lIGZyb20gTGFuZG1hcmsgVGltZSBwb2ludCAoTW9udGhzKSIsIGxlZ2VuZC5sYWJzPWMoIkFsbC10aW1lIG5lZ2F0aXZlIiwiTW9sZWN1bGFyIFJlY3VycmVuY2UiLCAiY3RETkEgTVJEIFBvc2l0aXZlIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDI0KSkKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MsIGxldmVscz1jKCIxIiwiMiIsIjMiKSwgbGFiZWxzID0gYygiQWxsLXRpbWUgbmVnYXRpdmUiLCJNb2xlY3VsYXIgUmVjdXJyZW5jZSIsICJjdEROQSBNUkQgUG9zaXRpdmUiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkgCnN1bW1hcnkoY294X2ZpdCkKCiNGaXNoZXIgdGVzdCBmb3IgREZTIHBlcmNlbnRhZ2VzIGF0IDEyIGFuZCAyNCBtb250aHMgLSBBbGwgdGltZSBuZWdhdGl2ZSB2cyBNb2xlY3VsYXIgUmVjdXJyZW5jZQpkZnNfdGltZXMgPC0gYygxMiwgMjQpCmNpcmNfZGF0YSA8LSBuYS5vbWl0KGNpcmNfZGF0YVssIGMoImN0RE5BLkR5bmFtaWNzIiwgIkRGUy5NUkQubW9udGhzIiwgIkRGUy5FdmVudCIpXSkKcF92YWx1ZXMgPC0gc2FwcGx5KGRmc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJBbGwtdGltZSBuZWdhdGl2ZSIgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiTW9sZWN1bGFyIFJlY3VycmVuY2UiICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gIkFsbC10aW1lIG5lZ2F0aXZlIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiTW9sZWN1bGFyIFJlY3VycmVuY2UiKQogIAogIG5lZ19zdXJ2IDwtIG5lZ190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gIkFsbC10aW1lIG5lZ2F0aXZlIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA8IHRpbWUpCiAgcG9zX3N1cnYgPC0gcG9zX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiTW9sZWN1bGFyIFJlY3VycmVuY2UiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzIDwgdGltZSkKICAKICBzdXJ2X21hdHJpeCA8LSBtYXRyaXgoYyhuZWdfc3VydiwgcG9zX3N1cnYsIG5lZ190b3RhbCAtIG5lZ19zdXJ2LCBwb3NfdG90YWwgLSBwb3Nfc3VydiksIG5yb3cgPSAyKQogIHRlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KHN1cnZfbWF0cml4KQogIHJldHVybih0ZXN0X3Jlc3VsdCRwLnZhbHVlKQp9KQpuYW1lcyhwX3ZhbHVlcykgPC0gcGFzdGUwKCJwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKCiNSZXBlYXQgYW5hbHlzaXMgdG8gcnVuIEZpc2hlciB0ZXN0IGZvciBBbGwgdGltZSBuZWdhdGl2ZSB2cyBjdEROQSBQb3NpdGl2ZQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBOQSAjZmlyc3Qgd2UgY3JlYXRlIHRoZSB2YXJpYWJsZSBmb3IgdGhlIGN0RE5BICYgTkFDIGNvbWJpbmF0aW9uLCBhbmQgd2UgYXNzaWduIHZhbHVlcwpjaXJjX2RhdGEgPC0gY2lyY19kYXRhICU+JQogIG11dGF0ZShjdEROQS5EeW5hbWljcyA9IGNhc2Vfd2hlbigKICAgIGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY3RETkEuU3VydmVpbGxhbmNlPT0iTkVHQVRJVkUiIH4gMSwKICAgIGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY3RETkEuU3VydmVpbGxhbmNlPT0iUE9TSVRJVkUiIH4gMiwKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiIH4gMwogICkpCgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuTVJELm1vbnRocz49MCxdCgpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygxMiwgMjQpKQpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcywgbGV2ZWxzPWMoIjEiLCIyIiwiMyIpLCBsYWJlbHMgPSBjKCJBbGwtdGltZSBuZWdhdGl2ZSIsIk1vbGVjdWxhciBSZWN1cnJlbmNlIiwgImN0RE5BIE1SRCBQb3NpdGl2ZSIpKQoKI0Zpc2hlciB0ZXN0IGZvciBERlMgcGVyY2VudGFnZXMgYXQgMTIgYW5kIDI0IG1vbnRocyAtIEFsbCB0aW1lIG5lZ2F0aXZlIHZzIGN0RE5BIFBvc2l0aXZlCmRmc190aW1lcyA8LSBjKDEyLCAyNCkKY2lyY19kYXRhIDwtIG5hLm9taXQoY2lyY19kYXRhWywgYygiY3RETkEuRHluYW1pY3MiLCAiREZTLk1SRC5tb250aHMiLCAiREZTLkV2ZW50IildKQpwX3ZhbHVlcyA8LSBzYXBwbHkoZGZzX3RpbWVzLCBmdW5jdGlvbih0aW1lKSB7CiAgbmVnX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gIkFsbC10aW1lIG5lZ2F0aXZlIiAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIHBvc19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJjdEROQSBNUkQgUG9zaXRpdmUiICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gIkFsbC10aW1lIG5lZ2F0aXZlIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiY3RETkEgTVJEIFBvc2l0aXZlIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJBbGwtdGltZSBuZWdhdGl2ZSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPCB0aW1lKQogIHBvc19zdXJ2IDwtIHBvc190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gImN0RE5BIE1SRCBQb3NpdGl2ZSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPCB0aW1lKQogIAogIHN1cnZfbWF0cml4IDwtIG1hdHJpeChjKG5lZ19zdXJ2LCBwb3Nfc3VydiwgbmVnX3RvdGFsIC0gbmVnX3N1cnYsIHBvc190b3RhbCAtIHBvc19zdXJ2KSwgbnJvdyA9IDIpCiAgdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3Qoc3Vydl9tYXRyaXgpCiAgcmV0dXJuKHRlc3RfcmVzdWx0JHAudmFsdWUpCn0pCm5hbWVzKHBfdmFsdWVzKSA8LSBwYXN0ZTAoInAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQoKI1JlcGVhdCBhbmFseXNpcyB0byBydW4gRmlzaGVyIHRlc3QgZm9yIE1vbGVjdWxhciBSZWN1cnJlbmNlIHZzIGN0RE5BIFBvc2l0aXZlCnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQoKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIE5BICNmaXJzdCB3ZSBjcmVhdGUgdGhlIHZhcmlhYmxlIGZvciB0aGUgY3RETkEgJiBOQUMgY29tYmluYXRpb24sIGFuZCB3ZSBhc3NpZ24gdmFsdWVzCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGEgJT4lCiAgbXV0YXRlKGN0RE5BLkR5bmFtaWNzID0gY2FzZV93aGVuKAogICAgY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjdEROQS5TdXJ2ZWlsbGFuY2U9PSJORUdBVElWRSIgfiAxLAogICAgY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjdEROQS5TdXJ2ZWlsbGFuY2U9PSJQT1NJVElWRSIgfiAyLAogICAgY3RETkEuTVJEID09ICJQT1NJVElWRSIgfiAzCiAgKSkKCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5NUkQubW9udGhzPj0wLF0KCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBjdEROQS5EeW5hbWljcywgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDEyLCAyNCkpCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzLCBsZXZlbHM9YygiMSIsIjIiLCIzIiksIGxhYmVscyA9IGMoIkFsbC10aW1lIG5lZ2F0aXZlIiwiTW9sZWN1bGFyIFJlY3VycmVuY2UiLCAiY3RETkEgTVJEIFBvc2l0aXZlIikpCgojRmlzaGVyIHRlc3QgZm9yIERGUyBwZXJjZW50YWdlcyBhdCAxMiBhbmQgMjQgbW9udGhzIC0gTW9sZWN1bGFyIFJlY3VycmVuY2UgdnMgY3RETkEgUG9zaXRpdmUKZGZzX3RpbWVzIDwtIGMoMTIsIDI0KQpjaXJjX2RhdGEgPC0gbmEub21pdChjaXJjX2RhdGFbLCBjKCJjdEROQS5EeW5hbWljcyIsICJERlMuTVJELm1vbnRocyIsICJERlMuRXZlbnQiKV0pCnBfdmFsdWVzIDwtIHNhcHBseShkZnNfdGltZXMsIGZ1bmN0aW9uKHRpbWUpIHsKICBuZWdfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiTW9sZWN1bGFyIFJlY3VycmVuY2UiICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgcG9zX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gImN0RE5BIE1SRCBQb3NpdGl2ZSIgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBuZWdfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiTW9sZWN1bGFyIFJlY3VycmVuY2UiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJjdEROQSBNUkQgUG9zaXRpdmUiKQogIAogIG5lZ19zdXJ2IDwtIG5lZ190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gIk1vbGVjdWxhciBSZWN1cnJlbmNlIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA8IHRpbWUpCiAgcG9zX3N1cnYgPC0gcG9zX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiY3RETkEgTVJEIFBvc2l0aXZlIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXMpCgojUmVwZWF0IHRvIGNvbXBhcmUgSFJzIGZvciBNb2xlY3VsYXIgUmVjdXJyZW5jZSB2cyBjdEROQSBNUkQgcG9zaXRpdmUKcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIE5BICNmaXJzdCB3ZSBjcmVhdGUgdGhlIHZhcmlhYmxlIGZvciB0aGUgY3RETkEgJiBOQUMgY29tYmluYXRpb24sIGFuZCB3ZSBhc3NpZ24gdmFsdWVzCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGEgJT4lCiAgbXV0YXRlKGN0RE5BLkR5bmFtaWNzID0gY2FzZV93aGVuKAogICAgY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjdEROQS5TdXJ2ZWlsbGFuY2U9PSJORUdBVElWRSIgfiAxLAogICAgY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjdEROQS5TdXJ2ZWlsbGFuY2U9PSJQT1NJVElWRSIgfiAyLAogICAgY3RETkEuTVJEID09ICJQT1NJVElWRSIgfiAzCiAgKSkKCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5NUkQubW9udGhzPj0wLF0Kc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MsIGxldmVscz1jKCIyIiwiMyIpLCBsYWJlbHMgPSBjKCJNb2xlY3VsYXIgUmVjdXJyZW5jZSIsICJjdEROQSBNUkQgUG9zaXRpdmUiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkgCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQpgYGAKCiNERlMgYnkgY3RETkEgYXQgdGhlIFN1cnZlaWxsYW5jZSBXaW5kb3cgLSBBbGwgc3RhZ2VzIExhbmRtYXJrIDEwIHdlZWtzCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UhPSIiLF0KY2lyY19kYXRhJERGUy5tb250aHM9Y2lyY19kYXRhJERGUy5tb250aHMtMi41CmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+Y3RETkEuU3VydmVpbGxhbmNlLCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5TdXJ2ZWlsbGFuY2UpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuU3VydmVpbGxhbmNlLCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiwicmVkIiksIHRpdGxlPSJERlMgLSBjdEROQSBTdXJ2ZWlsbGFuY2Ugd2luZG93IHwgQWxsIHN0YWdlcyIsIHlsYWI9ICJEaXNlYXNlLUZyZWUgU3Vydml2YWwiLCB4bGFiPSJUaW1lIGZyb20gTGFuZG1hcmsgVGltZSBwb2ludCAoTW9udGhzKSIsIGxlZ2VuZC5sYWJzPWMoImN0RE5BIE5lZ2F0aXZlIiwgImN0RE5BIFBvc2l0aXZlIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDI0KSkKY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLlN1cnZlaWxsYW5jZSwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKI0Zpc2hlciB0ZXN0IGZvciBERlMgcGVyY2VudGFnZXMgYXQgMTIgYW5kIDI0IG1vbnRocwpkZnNfdGltZXMgPC0gYygxMiwgMjQpCmNpcmNfZGF0YSA8LSBuYS5vbWl0KGNpcmNfZGF0YVssIGMoImN0RE5BLlN1cnZlaWxsYW5jZSIsICJERlMubW9udGhzIiwgIkRGUy5FdmVudCIpXSkKcF92YWx1ZXMgPC0gc2FwcGx5KGRmc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPT0gIlBPU0lUSVZFIiAmIGNpcmNfZGF0YSRERlMubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlID09ICJORUdBVElWRSIpCiAgcG9zX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlID09ICJQT1NJVElWRSIpCiAgCiAgbmVnX3N1cnYgPC0gbmVnX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPT0gIk5FR0FUSVZFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5tb250aHMgPCB0aW1lKQogIAogIHN1cnZfbWF0cml4IDwtIG1hdHJpeChjKG5lZ19zdXJ2LCBwb3Nfc3VydiwgbmVnX3RvdGFsIC0gbmVnX3N1cnYsIHBvc190b3RhbCAtIHBvc19zdXJ2KSwgbnJvdyA9IDIpCiAgdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3Qoc3Vydl9tYXRyaXgpCiAgcmV0dXJuKHRlc3RfcmVzdWx0JHAudmFsdWUpCn0pCm5hbWVzKHBfdmFsdWVzKSA8LSBwYXN0ZTAoInAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQpgYGAKCgoKCiNNdWx0aXZhcmlhdGUgY294IHJlZ3Jlc3Npb24gYXQgU3VydmVpbGxhbmNlIFdpbmRvdyBmb3IgREZTIC0gQWxsIHN0YWdlcyBMYW5kbWFyayAxMCB3ZWVrcwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlIT0iIixdCmNpcmNfZGF0YSRERlMubW9udGhzPWNpcmNfZGF0YSRERlMubW9udGhzLTIuNQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpLCBsYWJlbHMgPSBjKCJOZWdhdGl2ZSIsICJQb3NpdGl2ZSIpKQpjaXJjX2RhdGEkR2VuZGVyIDwtIGZhY3RvcihjaXJjX2RhdGEkR2VuZGVyLCBsZXZlbHMgPSBjKCJGZW1hbGUiLCAiTWFsZSIpKQpjaXJjX2RhdGEkQWdlLkdyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkQWdlLkdyb3VwLCBsZXZlbHMgPSBjKCIxIiwgIjIiKSwgbGFiZWxzID0gYygiPDcwIiwgIj43MCIpKQpjaXJjX2RhdGEkUHJpbVNpdGUgPC0gZmFjdG9yKGNpcmNfZGF0YSRQcmltU2l0ZSwgbGV2ZWxzID0gYygiTGVmdC1zaWRlZCBjb2xvbiIsICJSaWdodC1zaWRlZCBjb2xvbiIpKQpjaXJjX2RhdGEkRUNPRyA8LSBmYWN0b3IoY2lyY19kYXRhJEVDT0csIGxldmVscyA9IGMoIjAiLCAiMSIpKQpjaXJjX2RhdGEkcFQgPC0gZmFjdG9yKGNpcmNfZGF0YSRwVCwgbGV2ZWxzID0gYygiVDEtVDIiLCAiVDMtVDQiKSkKY2lyY19kYXRhJHBOIDwtIGZhY3RvcihjaXJjX2RhdGEkcE4sIGxldmVscyA9IGMoIk4wIiwgIk4xLU4yIikpCmNpcmNfZGF0YSRSQVMgPC0gZmFjdG9yKGNpcmNfZGF0YSRSQVMsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJXaWxkLVR5cGUiLCAiTXV0YW50IikpCnN1cnZfb2JqZWN0IDwtIFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpIApjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuU3VydmVpbGxhbmNlICsgR2VuZGVyICsgQWdlLkdyb3VwICsgRUNPRyArIHBUICsgcE4gKyBSQVMsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCwgZGF0YSA9IGNpcmNfZGF0YSwgbWFpbiA9ICJNdWx0aXZhcmlhdGUgUmVncmVzc2lvbiBNb2RlbCBmb3IgREZTIC0gQWxsIFN0YWdlcyIsIHJlZkxhYmVsID0gIlJlZmVyZW5jZSBHcm91cCIpCnRlc3QucGggPC0gY294LnpwaChjb3hfZml0KQpgYGAKCgojREZTIGJ5IGN0RE5BIER5bmFtaWNzIGZyb20gTVJEIHRvIDYgbW9udGhzIC0gYWxsIHN0YWdlcwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy42bW8ubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gTkEgI2ZpcnN0IHdlIGNyZWF0ZSB0aGUgdmFyaWFibGUgZm9yIHRoZSBjdEROQSAmIE5BQyBjb21iaW5hdGlvbiwgYW5kIHdlIGFzc2lnbiB2YWx1ZXMKY2lyY19kYXRhIDwtIGNpcmNfZGF0YSAlPiUKICBtdXRhdGUoY3RETkEuRHluYW1pY3MgPSBjYXNlX3doZW4oCiAgICBjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGN0RE5BLjZtb250aHMgPT0gIk5FR0FUSVZFIiB+IDEsCiAgICBjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLjZtb250aHMgPT0gIk5FR0FUSVZFIiB+IDIsCiAgICBjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGN0RE5BLjZtb250aHMgPT0gIlBPU0lUSVZFIiB+IDMsCiAgICBjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLjZtb250aHMgPT0gIlBPU0lUSVZFIiB+IDQKICApKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLjZtby5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+Y3RETkEuRHluYW1pY3MsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KGN0RE5BLkR5bmFtaWNzKSAlPiUKICBzdW1tYXJpc2UoCiAgICBUb3RhbCA9IG4oKSwKICAgIEV2ZW50cyA9IHN1bShERlMuRXZlbnQpLAogICAgRnJhY3Rpb24gPSBFdmVudHMgLyBuKCksCiAgICBQZXJjZW50YWdlID0gKEV2ZW50cyAvIG4oKSkgKiAxMDAKICApCnByaW50KGV2ZW50X3N1bW1hcnkpCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy42bW8ubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBjdEROQS5EeW5hbWljcywgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIsImdyZWVuIiwicHVycGxlIiwgInJlZCIpLCB0aXRsZT0iREZTIC0gY3RETkEgRHluYW1pY3MgZnJvbSBNUkQgdG8gNiBtb250aHMgfCBBbGwgU3RhZ2VzIiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiUGVyc2lzdGVudGx5IE5lZ2F0aXZlIiwgIkNvbnZlcnRlZCBOZWdhdGl2ZSIsIkNvbnZlcnRlZCBQb3NpdGl2ZSIsICJQZXJzaXN0ZW50bHkgUG9zaXRpdmUiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygyNCkpCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzLCBsZXZlbHM9YygiMSIsIjIiLCIzIiwgIjQiKSwgbGFiZWxzID0gYygiUGVyc2lzdGVudGx5IE5lZ2F0aXZlIiwgIkNvbnZlcnRlZCBOZWdhdGl2ZSIsIkNvbnZlcnRlZCBQb3NpdGl2ZSIsICJQZXJzaXN0ZW50bHkgUG9zaXRpdmUiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkgCnN1bW1hcnkoY294X2ZpdCkKYGBgCgoKI1RhYmxlIHdpdGggcmVjdXJyZW5jZSBzaXRlcyBieSBjdEROQSBhdCB0aGUgTVJEIFdpbmRvdwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkUkZTLkV2ZW50PT0iVFJVRSIsXQoKY2lyY19kYXRhX3N1YnNldDEgPC0gY2lyY19kYXRhICU+JQogIHNlbGVjdCgKICAgIFJlbC5TaXRlKSAlPiUKICBtdXRhdGUoCiAgICBSZWwuU2l0ZSA9IGZhY3RvcihSZWwuU2l0ZSwgbGV2ZWxzID0gYygiTG9jYWwiLCAiTHltcGggTm9kZSIsICJMaXZlciIsICJMdW5nIiwgIlBlcml0b25ldW0iLCAiQnJhaW4iKSkpCgpjaXJjX2RhdGFfc3Vic2V0MiA8LSBjaXJjX2RhdGEgJT4lCiAgc2VsZWN0KAogICAgUmVsLlNpdGUsCiAgICBjdEROQS5NUkQpICU+JQogIG11dGF0ZSgKICAgIFJlbC5TaXRlID0gZmFjdG9yKFJlbC5TaXRlLCBsZXZlbHMgPSBjKCJMb2NhbCIsICJMeW1waCBOb2RlIiwgIkxpdmVyIiwgIkx1bmciLCAiUGVyaXRvbmV1bSIsICJCcmFpbiIpKSwKICAgIGN0RE5BLk1SRCA9IGZhY3RvcihjdEROQS5NUkQsIGxldmVscyA9IGMoIk5FR0FUSVZFIiwgIlBPU0lUSVZFIikpKQpPdmVyYWxsIDwtIGNpcmNfZGF0YV9zdWJzZXQxICU+JQogIHRibF9zdW1tYXJ5KAogICAgc3RhdGlzdGljID0gbGlzdCgKICAgICAgYWxsX2NvbnRpbnVvdXMoKSB+ICJ7bWVkaWFufSAoe21pbn0gLSB7bWF4fSkiLAogICAgICBhbGxfY2F0ZWdvcmljYWwoKSB+ICJ7bn0gKHtwfSUpIikpICU+JQogIGJvbGRfbGFiZWxzKCkKT3ZlcmFsbAoKQnljdEROQV9NUkQgPC0gY2lyY19kYXRhX3N1YnNldDIgJT4lCiAgdGJsX3N1bW1hcnkoCiAgICBieSA9IGN0RE5BLk1SRCwgIyBhZGQgdGhpcyBsaW5lIHRvIHN1Ymdyb3VwIGJ5IGN0RE5BLk1SRAogICAgc3RhdGlzdGljID0gbGlzdCgKICAgICAgYWxsX2NvbnRpbnVvdXMoKSB+ICJ7bWVkaWFufSAoe21pbn0gLSB7bWF4fSkiLAogICAgICBhbGxfY2F0ZWdvcmljYWwoKSB+ICJ7bn0gKHtwfSUpIikpICU+JQogIGFkZF9wKCkgJT4lCiAgYm9sZF9sYWJlbHMoKQpCeWN0RE5BX01SRAoKbWVyZ2VkX3RhYmxlIDwtIHRibF9tZXJnZSh0YmxzPWxpc3QoT3ZlcmFsbCwgQnljdEROQV9NUkQpKQptZXJnZWRfdGFibGUKCmZpdDEgPC0gYXNfZmxleF90YWJsZSgKICBtZXJnZWRfdGFibGUsCiAgaW5jbHVkZSA9IGV2ZXJ5dGhpbmcoKSwKICByZXR1cm5fY2FsbHMgPSBGQUxTRSkKZml0MQpzYXZlX2FzX2RvY3goZml0MSwgcGF0aD0gIn4vRG93bmxvYWRzL21lcmdlZF90YWJsZS5kb2N4IikKYGBgCgoKI01UTS9tTCBsZXZlbHMgYXQgdGhlIE1SRCBXaW5kb3cgYnkgUmFkaW9sb2dpY2FsIFJlY3VycmVuY2UKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLk1SRC5tb250aHM+PTAsXQpjaXJjX2RhdGEgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgojIFRyYW5zZm9ybSBwX01SRF9NVE0gd2l0aCBsb2cxMApjaXJjX2RhdGEkcF9NUkRfTVRNIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGNpcmNfZGF0YSRwX01SRF9NVE0pKQpjaXJjX2RhdGEkUkZTLkV2ZW50IDwtIGZhY3RvcihjaXJjX2RhdGEkUkZTLkV2ZW50LCBsZXZlbHMgPSBjKCJGQUxTRSIsICJUUlVFIiksIGxhYmVscyA9IGMoIk5vIFJlY3VycmVuY2UiLCAiUmVjdXJyZW5jZSIpKQpzdW1tYXJ5X3N0YXRzIDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShSRlMuRXZlbnQpICU+JQogIHN1bW1hcmlzZSgKICAgIG1lZGlhbl9wX01SRF9NVE0gPSBtZWRpYW4ocF9NUkRfTVRNLCBuYS5ybSA9IFRSVUUpLAogICAgcmFuZ2VfcF9NUkRfTVRNID0gcGFzdGUwKG1pbihwX01SRF9NVE0sIG5hLnJtID0gVFJVRSksICIgLSAiLCBtYXgocF9NUkRfTVRNLCBuYS5ybSA9IFRSVUUpKQogICkKcHJpbnQoc3VtbWFyeV9zdGF0cykKCm0zXzF2MiA8LSB3aWxjb3gudGVzdChwX01SRF9NVE0gfiBSRlMuRXZlbnQsCiAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gY2lyY19kYXRhW2NpcmNfZGF0YSRSRlMuRXZlbnQgJWluJSBjKCJObyBSZWN1cnJlbmNlIiwgIlJlY3VycmVuY2UiKSwgXSwKICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkKcHJpbnQobTNfMXYyKQpib3hwbG90KHBfTVJEX01UTX5SRlMuRXZlbnQsIGRhdGE9Y2lyY19kYXRhLCBtYWluPSJjdEROQSBNUkQgV2luZG93IE1UTSAtIFJlY3VycmVuY2UiLCB4bGFiPSJSZWN1cnJlbmNlIiwgeWxhYj0iTVRNL21MIiwgY29sPSJ3aGl0ZSIsYm9yZGVyPSJibGFjayIsIHlsaW0gPSBjKDAsIDUwKSkKYGBgCgojTVRNL21MIGxldmVscyBhdCB0aGUgTVJEIFdpbmRvdyBieSBSYWRpb2xvZ2ljYWwgUmVjdXJyZW5jZSBTaXRlcwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkUkZTLkV2ZW50PT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLk1SRC5tb250aHM+PTAsXQpjaXJjX2RhdGEgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgojIFRyYW5zZm9ybSBwX01SRF9NVE0gd2l0aCBsb2cxMApjaXJjX2RhdGEkcF9NUkRfTVRNIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGNpcmNfZGF0YSRwX01SRF9NVE0pKQpjaXJjX2RhdGEkUmVsLlNpdGUgPC0gZmFjdG9yKGNpcmNfZGF0YSRSZWwuU2l0ZSwgbGV2ZWxzID0gYygiTGl2ZXIiLCAiTHltcGggTm9kZSIsICJMb2NhbCIsICJQZXJpdG9uZXVtIiwgIkx1bmciLCAiQnJhaW4iKSkKc3VtbWFyeV9zdGF0cyA8LSBjaXJjX2RhdGEgJT4lCiAgZ3JvdXBfYnkoUmVsLlNpdGUpICU+JQogIHN1bW1hcmlzZSgKICAgIG1lZGlhbl9wX01SRF9NVE0gPSBtZWRpYW4ocF9NUkRfTVRNLCBuYS5ybSA9IFRSVUUpLAogICAgcmFuZ2VfcF9NUkRfTVRNID0gcGFzdGUwKG1pbihwX01SRF9NVE0sIG5hLnJtID0gVFJVRSksICIgLSAiLCBtYXgocF9NUkRfTVRNLCBuYS5ybSA9IFRSVUUpKQogICkKcHJpbnQoc3VtbWFyeV9zdGF0cykKa3J1c2thbF90ZXN0IDwtIGtydXNrYWwudGVzdChwX01SRF9NVE0gfiBSZWwuU2l0ZSwgZGF0YSA9IGNpcmNfZGF0YSkKcHJpbnQoa3J1c2thbF90ZXN0KQpib3hwbG90KHBfTVJEX01UTX5SZWwuU2l0ZSwgZGF0YT1jaXJjX2RhdGEsIG1haW49ImN0RE5BIE1SRCBXaW5kb3cgTVRNIC0gUmVjdXJyZW5jZSBTaXRlIiwgeGxhYj0iUmVjdXJyZW5jZSBTaXRlIiwgeWxhYj0iTVRNL21MIiwgY29sPSJ3aGl0ZSIsYm9yZGVyPSJibGFjayIsIHlsaW0gPSBjKDAsIDQwKSkKYGBgCgojQmFycGxvdCB3aXRoIFJlY3VycmVuY2UgU2l0ZXMgKExpdmVyIHZzIE90aGVycykgYnkgY3RETkEgYXQgdGhlIE1SRCBXaW5kb3cKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJFJGUy5FdmVudD09IlRSVUUiLF0KCmNpcmNfZGF0YSRjdEROQS5NUkQgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5NUkQsIGxldmVscyA9IGMoIk5FR0FUSVZFIiwgIlBPU0lUSVZFIiksIGxhYmVscyA9IGMoIk5lZ2F0aXZlIiwgIlBvc2l0aXZlIikpCmNpcmNfZGF0YSRSZWwuU2l0ZSA8LSBmYWN0b3IoY2lyY19kYXRhJFJlbC5TaXRlLCBsZXZlbHMgPSBjKCJMaXZlciIsICJMeW1waCBOb2RlIiwgIkxvY2FsIiwgIlBlcml0b25ldW0iLCAiTHVuZyIsICJCcmFpbiIpKQpjb250aW5nZW5jeV90YWJsZSA8LSB0YWJsZShjaXJjX2RhdGEkUmVsLlNpdGUsIGNpcmNfZGF0YSRjdEROQS5NUkQpCmNoaV9zcXVhcmVfdGVzdCA8LSBjaGlzcS50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChjaGlfc3F1YXJlX3Rlc3QpCmZpc2hlcl9leGFjdF90ZXN0IDwtIGZpc2hlci50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChmaXNoZXJfZXhhY3RfdGVzdCkKcHJpbnQoY29udGluZ2VuY3lfdGFibGUpCnRhYmxlX2RmIDwtIGFzLmRhdGEuZnJhbWUoY29udGluZ2VuY3lfdGFibGUpCnRhYmxlX2RmJFRvdGFsIDwtIGF2ZSh0YWJsZV9kZiRGcmVxLCB0YWJsZV9kZiRWYXIxLCBGVU4gPSBzdW0pCnRhYmxlX2RmJFBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkRnJlcSAvIHRhYmxlX2RmJFRvdGFsCnRhYmxlX2RmJE1pZGRsZVBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkUGVyY2VudGFnZSAvIDIKZ2dwbG90KHRhYmxlX2RmLCBhZXMoeCA9IFZhcjEsIHkgPSBQZXJjZW50YWdlLCBmaWxsID0gVmFyMikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dChhZXMoeSA9IE1pZGRsZVBlcmNlbnRhZ2UsIGxhYmVsID0gRnJlcSksIHBvc2l0aW9uID0gInN0YWNrIiwgY29sb3IgPSAiYmxhY2siLCB2anVzdCA9IDEuNSwgc2l6ZSA9IDcpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiUGF0aWVudHMgd2l0aCBSYWRpb2xvZ2ljYWwgUmVjdXJyZW5jZSIsIAogICAgICAgeCA9ICJSZWN1cnJlbmNlIFNpdGUiLCAKICAgICAgIHkgPSAiUGF0aWVudHMgKCUpIiwgCiAgICAgICBmaWxsID0gImN0RE5BIGF0IE1SRCIsCiAgICAgICBjYXB0aW9uID0gcGFzdGUoIkNoaS1zcXVhcmVkIHRlc3QgcC12YWx1ZTogIiwgZm9ybWF0LnB2YWwoY2hpX3NxdWFyZV90ZXN0JHAudmFsdWUpKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJOZWdhdGl2ZSIgPSAiYmx1ZSIsICJQb3NpdGl2ZSIgPSAicmVkIikpICsgIyBkZWZpbmUgY3VzdG9tIGNvbG9ycwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLjUsIHNpemUgPSAxNCksICMgaW5jcmVhc2UgeC1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB4LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIGxhYmVsIHNpemUKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikpICAjIGluY3JlYXNlIFJlY3VycmVuY2UgbGFiZWwgc2l6ZQpgYGAKCiNEZXRlY3Rpb24gY3RETkEgcmF0ZXMgYmFzZWQgb24gc2l0ZXMgb2YgcmVsYXBzZQpgYGB7cn0KIyBSZW1vdmUgZXhpc3Rpbmcgb2JqZWN0cyBhbmQgc2V0IHRoZSB3b3JraW5nIGRpcmVjdG9yeQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRSRlMuRXZlbnQ9PSJUUlVFIixdCgojIENyZWF0ZSBhIHRhYmxlIG9mIGNvdW50cyBmb3IgdGhlICJSZWwuU2l0ZSIgdmFyaWFibGUKcmVsc2l0ZV9jb3VudHMgPC0gdGFibGUoY2lyY19kYXRhJFJlbC5TaXRlKQpyZWxzaXRlX2RmIDwtIGFzLmRhdGEuZnJhbWUocmVsc2l0ZV9jb3VudHMpCm5hbWVzKHJlbHNpdGVfZGYpIDwtIGMoIlJlbC5TaXRlIiwgIkNvdW50IikKY2lyY19kYXRhX3Bvc19tcmQgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQ9PSJQT1NJVElWRSIsXQpjaXJjX2RhdGFfcG9zX2FueXRpbWUgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hbnl0aW1lPT0iUE9TSVRJVkUiLF0KcG9zX2NvdW50c19tcmQgPC0gdGFibGUoY2lyY19kYXRhX3Bvc19tcmQkUmVsLlNpdGUpCnBvc19jb3VudHNfYW55dGltZSA8LSB0YWJsZShjaXJjX2RhdGFfcG9zX2FueXRpbWUkUmVsLlNpdGUpCnJlbHNpdGVfZGYkTVJEUG9zX0NvdW50IDwtIGlmZWxzZShpcy5uYShtYXRjaChyZWxzaXRlX2RmJFJlbC5TaXRlLCBuYW1lcyhwb3NfY291bnRzX21yZCkpKSwgMCwgcG9zX2NvdW50c19tcmRbbWF0Y2gocmVsc2l0ZV9kZiRSZWwuU2l0ZSwgbmFtZXMocG9zX2NvdW50c19tcmQpKV0pCnJlbHNpdGVfZGYkTVJEUG9zX0NvdW50W2lzLm5hKHJlbHNpdGVfZGYkTVJEUG9zX0NvdW50KV0gPC0gMApyZWxzaXRlX2RmJEFueXRpbWVQb3NfQ291bnQgPC0gaWZlbHNlKGlzLm5hKG1hdGNoKHJlbHNpdGVfZGYkUmVsLlNpdGUsIG5hbWVzKHBvc19jb3VudHNfYW55dGltZSkpKSwgMCwgcG9zX2NvdW50c19hbnl0aW1lW21hdGNoKHJlbHNpdGVfZGYkUmVsLlNpdGUsIG5hbWVzKHBvc19jb3VudHNfYW55dGltZSkpXSkKcmVsc2l0ZV9kZiRBbnl0aW1lUG9zX0NvdW50W2lzLm5hKHJlbHNpdGVfZGYkQW55dGltZVBvc19Db3VudCldIDwtIDAKcmVsc2l0ZV9kZiRQZXJjZW50IDwtIChyZWxzaXRlX2RmJENvdW50IC8gc3VtKHJlbHNpdGVfZGYkQ291bnQpKSAqIDEwMApyZWxzaXRlX2RmJE1SRFBvc19QZXJjZW50IDwtIChyZWxzaXRlX2RmJE1SRFBvc19Db3VudCAvIHJlbHNpdGVfZGYkQ291bnQpICogMTAwCnJlbHNpdGVfZGYkQW55dGltZVBvc19QZXJjZW50IDwtIChyZWxzaXRlX2RmJEFueXRpbWVQb3NfQ291bnQgLyByZWxzaXRlX2RmJENvdW50KSAqIDEwMAp0b3RhbF9vYnNlcnZhdGlvbnMgPC0gc3VtKHJlbHNpdGVfZGYkQ291bnQpCnRvdGFsX3Bvc19tcmQgPC0gc3VtKHJlbHNpdGVfZGYkTVJEUG9zX0NvdW50KQp0b3RhbF9wb3NfYW55dGltZSA8LSBzdW0ocmVsc2l0ZV9kZiRBbnl0aW1lUG9zX0NvdW50KQp0b3RhbF9yb3cgPC0gZGF0YS5mcmFtZShSZWwuU2l0ZSA9ICJUb3RhbCIsIENvdW50ID0gdG90YWxfb2JzZXJ2YXRpb25zLCBNUkRQb3NfQ291bnQgPSB0b3RhbF9wb3NfbXJkLCBBbnl0aW1lUG9zX0NvdW50ID0gdG90YWxfcG9zX2FueXRpbWUsIFBlcmNlbnQgPSAxMDAsIE1SRFBvc19QZXJjZW50ID0gKHRvdGFsX3Bvc19tcmQgLyB0b3RhbF9vYnNlcnZhdGlvbnMpICogMTAwLCBBbnl0aW1lUG9zX1BlcmNlbnQgPSAodG90YWxfcG9zX2FueXRpbWUgLyB0b3RhbF9vYnNlcnZhdGlvbnMpICogMTAwKQpyZWxzaXRlX2RmIDwtIHJiaW5kKHJlbHNpdGVfZGYsIHRvdGFsX3JvdykKcHJpbnQocmVsc2l0ZV9kZikKCmZ0IDwtIGZsZXh0YWJsZShyZWxzaXRlX2RmKQpkb2MgPC0gcmVhZF9kb2N4KCkgJT4lCiAgYm9keV9hZGRfZmxleHRhYmxlKHZhbHVlID0gZnQpCnByaW50KGRvYywgdGFyZ2V0ID0gInJlbHNpdGVfZGYuZG9jeCIpCmBgYAoK